{"_id":"@joist/component","_rev":"346-9f3335833cedc404808094fc59d10614","name":"@joist/component","dist-tags":{"latest":"1.8.10","canary":"2.0.1-next.1637803026.0","next":"1.1.4-alpha.0"},"versions":{"1.0.0-alpha.0":{"name":"@joist/component","version":"1.0.0-alpha.0","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^2.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.0"},"gitHead":"dc4f26a409e76032a92208b071d8cb851fc0e0e3","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.0","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-U0iCbYGV7tTobJqg9o8l33nBaU+NI56gZZvAVM8ump3A57YxD6sJxL/Vu//gm9OQUVTjLUp652COwIiDmtKYZA==","shasum":"305a576746862f04039a93ada208e73166b021b8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.0.tgz","fileCount":53,"unpackedSize":65478,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeqeMBCRA9TVsSAnZWagAA0OYP/Auk/zMOxy/WUw9d94a0\nB5yr0jAhBHCZCyQraGw/usjwG1QMrRXHHNj0juOzMtnsFEBJwJthG5oQEQUP\nH4TDWnVQSORRmJDxYiVHwJf+V15CuD/31Ad7cxttgqXjnR3OmhQT7VHhqn5i\nqMRS9UPcubzbuRlkw7YzHeb+LisJz7ePO7azKaI772sJUgXq7/yC811i6lSC\nG+hgPpm4FIqha5Ele4qVskinammj9joMjqDqt/HZKipXu0XOFmQYyzzLveXn\nvRghvbUxJERs6FEYcPmuK5PZIQxWWvo6nCSY1CxZuyqrKSde57rAkuY2bKOk\nRsw6xOfBEyIn2ToU+zI6EBnAdjDoZrRAuHY2FZQkMXXZqhfEPg59Uf9iPlGL\njhwM5ec4m8dmtF8AJcrnRjGL0y7RXIqwOBUmCWyvr9huWPwJ7GLaJ2r1EdPD\nREgU0JMvMogiF2TzwgPxkzDGxcruSrXE8zHH4Zd3mYaOQ88c5Y++UI0GSdVQ\nt5x3iGvNEjfaJiQ+QjlftM2A1PItMet0iXRJ1GAbHz9itYFMflvaGWQfYgAZ\nZThIaRsJ916JjFAmNX2M9DzivzsvAa55nVopunmLB+2rHAaMfr6j5WndhSsz\n3dyBw791p+Sjlv8bYAeabCyUl/Jc1fp3NjOgDSOZEcsGgUZyKlL2Tq4Whfu4\nQI2M\r\n=VoS+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDbXtHKxD8yvZAKKBuCFbUHvKsKKwC5HLiUP8XMBReLjAIgeJx0UeMKsqZzwJbNx9cVn5Aa8LM+gK89Cwk0/WCI84o="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.0_1588192001141_0.0997323909203447"},"_hasShrinkwrap":false},"1.0.0-alpha.1":{"name":"@joist/component","version":"1.0.0-alpha.1","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^2.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.1"},"gitHead":"94cde07b2b2426433feb16d8aa73ceaa54c60c79","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.1","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-2Zy00TojSnGTOzyIPvHLXNG+3zlCPYsYVfNXkG88N1TnWlvXGHqx/buepFzk5ywlcKLMDOTrAW8rSs1NT/4lLQ==","shasum":"11fbaa1209385e42c19976f5e46a0ff610d591d8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.1.tgz","fileCount":53,"unpackedSize":65478,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeqfHjCRA9TVsSAnZWagAArJ4P+gM/B1NOlIPgYh+m9nxb\n9GpTb/YHaFT1qtb3ZTFXIjzdUhTiBfCw27XWVt95HjuNW7oyEvWCSr9dTc6p\nVStMN48kervdV5kSj9tRIx+IzuB1JeuhPD0M4Z04u3J2m53huer42wDLVJvt\nJZrSwBzDp+hSOFZc5HDS3U5fqZtuhRrmoo5TLkq2AWdGZbMNU0IKNKO5YQvx\n19QECIeiP7DoVYZZ46+mCJYqpHxKOQ0C3Yj0k3XO5HwowLJnKJfEXI5qp1HC\nJv1AHx2NtSlW3eXjstH+b8ZOQtSIx+QsCpnnLBWKHFGyXMuGsRVJuyXqzlnn\nXFLU/a4LS8PrpQMjAsDrizux1vt7vZL3X91R1dqfogKp2p0a87SFDYLBBeR4\n9oB4LfrLmo9neIugyI7XI7n8+prO7/Vf6fHVJB5CR0Glog88lH6zzRcOqY9l\neJyQICnBIjhRiBr1j0Netq9guvJMva37yN1XT+rUoH8f2O6P6C1jUfKkSW8i\nr8TvFqdHxCRJL2hEDgI04mDf9rYA+gUXU/wfUzKiDZYsZHU3heYy2N9nR+Y/\nezcdM7e1OIqLr5Ifq3yWwV1PFc+/4OD8mDSUW7cdR6NWAj88qMyw6l9ey41Y\n9UnvN/dyp4oFLLw73YWko0BSSN3iu7cOPa6PtWcA7+Hh4N/g6d3ROmPc3+Om\nh8vr\r\n=YK/X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDRv3ztYfjZVoaVp8nOPsQvbY2zpAy2L8c1nhWdLdak/QIhAOsCA62j1eSpvJGs4A2wMRcuC6oXLC9HTUv40UNr1fLT"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.1_1588195811178_0.6016628848379519"},"_hasShrinkwrap":false},"1.0.0-alpha.2":{"name":"@joist/component","version":"1.0.0-alpha.2","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^2.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.2"},"gitHead":"136543b7e3aa3e43ed303e3ffa4661140c65383e","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.2","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-y+0zwzNjiJycrC2uI0ggslgMSEhQOVeDN2faGz9pYq5Pytn3cgOrElzjltd6xf+yMRwU+1FexnUZeU2Bp+GW+A==","shasum":"0da5d0c7365f3c056fbe3abfd1f555b2180c5c2e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.2.tgz","fileCount":53,"unpackedSize":65478,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeqfO0CRA9TVsSAnZWagAATeMP/jvT8MoYiK72NaVuYDFG\nkol1VIRZlS09bTHQ24MwOPz2Rtdt/HPVvXnjv0aA61LtBSs9TNfDld0qeZJR\nVyc1dzSbU1s2Np7XSiYIZgUfvI7Y+tujIG655nuKsJJVTxsm8DPK9b4Ty+rN\nxKd8g9z/u3vQ38NSzST+AqhVrzZMj9qjip7Oj7K6PawJbBcYAgRnnQbZItWu\nFEjByeCH+vwHvHgnI7wdSRquzeYzpxQFnvH4VIi7zyywPUNIhwm4wmfodQva\nSFozg7MmrcrLx9rmW+8bpqYAeH6Zy9KyQWokGwJs2UmTuy6GpTfzbADz54Cx\nwhvxBLAwuOEXUfCDsaKhGnI46Xye18o+K/WKduFjSQAY7ruKUlhyaftyxrCg\n+XPct+kpaZmuFXa3Gqxz1a+FmSqL1VZJagQreVcM7RfojugRxY8J1ztA1tRn\n9MYedoRtIAZLCuVyNJKdsG8e+vt4QWvuNidbinQyLvPbKP1OgTtERLHpI9f9\nqnqpsN/zbUIbraPbCdsuMCP+i8TlA/7k+jo9rBTO/A+rMJESY8nmuX6L7YI/\nuUWIoS2IQxsory6VLQ2lApQAgrXdwCsZq5rr/JeyxwChCcqf4VPuJ2aoosYp\nh90zosw2fIGoSxFvJS+ZCU5cR/WxakNbaA/aTTv4Hu5SA8HyrOY8A+CqB1KW\nHNIe\r\n=Ckmj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCKPSfb832NkBW7AJtRDNvncGE7VML2LV3cymYUPZ6BswIgL+GImWpInFFye/S/ctXHH9vLbTP9hawzAOjVU6ZX2ws="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.2_1588196276320_0.09869183861984077"},"_hasShrinkwrap":false},"1.0.0-alpha.3":{"name":"@joist/component","version":"1.0.0-alpha.3","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.3"},"gitHead":"0d8f6ef10be125e160b768be77d9b1dd6d45b39a","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.3","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-0lZD25BiozOCGZ65TAwEhDNudNFwOJdhdpA5crOV0UMqvB5VnwC8iVpHlcU7C0662fZmrd3YllyKHYfCG5GA8g==","shasum":"1436b2aaf3365c7de42fae529e5896660528f357","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.3.tgz","fileCount":53,"unpackedSize":65216,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeq4bICRA9TVsSAnZWagAAB1YP/jumWrt0JOsP7pqdiI4J\nvajhkRKDN5Kc9R+5ja0dxVn0NERxcJ55+Do/NWhhtQAw3D4RRovW1wPsaGbn\nzn/xhhTochaLBmRmx8jaDA6amincerlCgXNBm/tY6WP6LW/GWMGgV+MMoOT/\nzF3Hl7YEXeYj+B7C0MCBGuos+xu7aKY6R41ODbB8/CgnSJ4cRPRWu05ysqt3\nCsP3cjAOvBiLyQ4S7ygJRZfPVTBfQFnO8L9XkWjZgncH0HJBbvyWyiQYxraB\nj+0GfbONp2ERmCyyheHrVYcFUIg6y12zJnLg8nAVnyVhVngCQzwVUpxmk7GQ\n3tqycqsvN7NGfz2Uyyspwo2tyqCHJ0yU5THqjV52pGW+go0n8YvARYd6xGk8\nm2jGxvgOIplAoFPhjg8vVbhoOROJzeVmz4Dw4npYRVg/YVnGOVclqYKGalN3\nh8+WgjU300OVEBMUacBDl2E1B2+TE/v6gRNSgwNKrylCCQHyp5cj0pTjMYrd\nA2L4mJjQBBFg5rYUAWpRda+XT+gkdMLew0I/rSk9lIyrk6PSM5qR1iiWdzn2\nKtMMJz+0DVIo0ZkXO25KF3uur+EmwOgWPHAbV2oRZhYgrjMDrkac4StdKCTV\nvDkql+SGxpd4GEktaWmIMNqCP4sPpDn7C6tu+EazJJ6t+BNu0QEJn9WpG0/K\nD6oS\r\n=OzCC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCvzCAgm0k0MDwmb4k6epJs/QjRTi3ff6OW/4ltD+0u1gIgYPUqJoClwCueFxbRtJ3+Er0kKX25zkDrbIBtHK5kISw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.3_1588299463835_0.032934190449736445"},"_hasShrinkwrap":false},"1.0.0-alpha.4":{"name":"@joist/component","version":"1.0.0-alpha.4","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.4"},"gitHead":"7a17c71cb8f6dd054fe2ed89c1c667ad15d2f801","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.4","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-6ImQ9hBS3GVrQRrJCK4+/vjcclYGyH8kVsbDjWQikLRLHa6INCeGww5AYwGqCBfAi9UHRhyVdk8LsamZ7FRXvw==","shasum":"f7cda7b2340992b5b27483056f98b28087d54618","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.4.tgz","fileCount":53,"unpackedSize":65227,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJerAyCCRA9TVsSAnZWagAA+AMP/00l2aN1ZKV9EaNm8P4r\nqCC+Q8jIOmgsqfoyhnR6wal1ZijOZTNnRY4fzPW2Qz419xc1+qWMQj3qKVse\nD55Dhhh63ooYETG6eUnO0wSkZRPDc/zNY8Y1lEfYlo0dUdNq1v0AxQkkZaL8\nc3vOeGU/BdL/W9vzMfIoexs8zuJEHoQ3FE7Hf/TY6a56+z1Lx6S4uVSkYB3P\ns79ktargA46LPXihDp4dsZJq2HmiiC7I1fSYIg/Me+xj243htcC/tQ3EWrug\nWxU/g7JzZO5oTEg9ml87QC+euHTK5cdZwy8/Dv3K8mV3tiTEZCtx+Xnn6QgY\nSF3C2+ILO7tQy1GkcgzFmvfwvrjMD6iWNznJ8Sf25OrCgHxyFXucN+Y8XeM1\nC0FHD8O4Ctkz993D8xtUWyF1/4M0RptLmeVa2VIw2qhjqB/aqAxEJKQmhvPu\n7h+FSw4gkBtQe4J6e1XAGRJPRuj1LHnevSk69xAIgPHR5yGV7+Nc/3VDtBvM\nsKFU2B56k0zGlOnDlk52ot3KdcGkJupAbFMnvYf0GQDXza4cAcYyh9kL7nXt\nJ8TmKllage+udgkM42KelHEIC6AFfskzUgoKepnvsuuPyRKujLiwzP3itg/g\n5IfxSMq/aC7yVyLraFSnHto9WvWKxY3EBtKH/TIIvRlAMPLY0ilMZSUlyi2E\nHh5f\r\n=+qOc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDQInhQeLqr+mRbmmeHcSiXduA1/zCfALrx8oKMNGfENAiBrYwGjQU+88pV+wAnyusJ1OfJepzoiCwRbHJl/nErEyg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.4_1588333697885_0.9125714174663946"},"_hasShrinkwrap":false},"1.0.0-alpha.5":{"name":"@joist/component","version":"1.0.0-alpha.5","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.5"},"gitHead":"27c11674ff08243dc1db3f61440336a16f8239ac","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.5","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-vbd15KIqJPjMbsI+EPc2neUrWFDr8XK44YvVKwj3gtLdGCPiiV0Pf/qzcfLMQyR8/jxcagxNedLU5EWlWaP5hw==","shasum":"c30bfade4e964c5ec3964b1fae41fd7340452e2f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.5.tgz","fileCount":53,"unpackedSize":65102,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJerYbmCRA9TVsSAnZWagAAmb0P/RaGBUmrNC7mZb5ni7Lf\nEF5berCWczEFltmZ5REw+G2x7Mu17CjZynzQOEy4CRRbMS/WgfosFD35+xzW\nxmapU2uQ7Qjan9/mUmCkiRlbmd1zyEL6uef3pas1Cwr3NE6KJp0rFwvfwF26\nQC4gMYiwrYb5POu5s5LEr5q7PSl+5PJrXG4xTbb3tsdyMA5lET9Rsc4IpPmD\nr1LRV0GGws4QscFN7YpKcdVfiJKGVyURHy246syU9ua15gtaGJx19lpdigr2\n1jNLIajUsB/javCLf+h1jfpPeqa6JnxM23fjzvp3nQc0JxpzJ98dU3P4bWEw\nQ0BZjoL9GhNVlxNePffTOnqlzcW7Wek1+n4thSeg7fBk19hQY55ieIDMZV/z\n0nc7lgBKkoCy1VtQuss4v/yx4hbGQ0jf4NzL2dIi34cHp5Y1gnjkTewJbfHa\npVNqRvY5gb5M5/qRlrFky/SAM3kWF8gaORnRU4dAZ5FYVvhEWVzOPPXL/578\n5u412Vx9QJcUGZMxh8XQE1L4uFN2lD0121PQJnpq5ZFzgEfpp97Zf6HjmWl7\nLNo/iVvVNjnZPiXdWNgV3Hwn4ONL4Dam5ZPwI3r+7mFh7tvLo+ua6EgA1P5u\nU453mxTF2/v1Ws4SOOtHnznBJ9IhOCfNUEOfJ6ehLm4SYo3DxJqvbityIhQI\nqHRs\r\n=UgkN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDtdUvERA/NsyUcF595fxXgiB+Mu69pYNwPkejdlisMWAiAXzxjFFg/TSZwN5dt8NrFbaX0+nv+Wj9I984B7mkGoUw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.5_1588430565547_0.05742121115918808"},"_hasShrinkwrap":false},"1.0.0-alpha.6":{"name":"@joist/component","version":"1.0.0-alpha.6","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.6"},"gitHead":"2d708cb6215a73cb300a610220db1171aa2fa602","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.6","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-OzsEX85Vp7bPsvb4qGVyf9uRo3EWgA5x9uJCD2X6dZrecWE/nXtZLCUxc+8ij19nCac9+MBc26YdyW9XlLmHCw==","shasum":"ae542c60842411991adb88291cdd53ab5ea287b0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.6.tgz","fileCount":53,"unpackedSize":65102,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJergLbCRA9TVsSAnZWagAAPgQQAIqZeXCb6pAc+IByLCRj\nGuFwfbxjdvJgWQxz/B8Jdu4JEka4sCzEprUiO99yul6b2lbq7pmkpbbU74+K\nzuw0YjHGOTOI9gBYMQan5cPZijPqQppD06Lo5ZpacOLms8bkoKio2ZpYj5Gu\nDqLs/Ux1PcSirv+lQD9ihjVEnNnumfCAHTf3Sl5uWPBCtKpx2cpZDS4asDVA\n7OMIiMZKquAccBLtsTWx24qSuAx+JiqBW/+r89/rG+nJe6ulkJH47RsOkYF4\n2ukk5F0ezdXJfJhoZDn8M1qd0H4rpt8IerUbb8R7C21SkTaBzimUMRvAzjsL\ne9klb2j8R37xWhrGr4OoIfSypryI4fi6NR0DuGaCXltPaDzd1Gdu9T+OEeR9\n1TNyatmdVpp+A6F62ODlO+hvmc/Mk9Rkd9UTEpM9YTUGfGZnwM9bMDlTKJyz\n8KZQrU/CYbw57JtxGFt3IaOLUaGTSyor5//P06j91aLKvSTr4C/jJTN2Uk89\nhz9RLIEHxHGvSswxgLlh+EGEQkIIexbMaJLBssAUEJsgAj79MRXrFH/hBQdp\nDNZUP98a6taA3zYP4MIm+mTwusArHrgJ+EZbeXkJfUGq5FKGmEu+CwRhGHjF\n5M8PqzxIzUhU78rGlrXwLGij5H4ztmVGy/zixR/hC2MbJrV6eFjjYv8K7JXm\nRIEy\r\n=SF8P\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAIU8zpwygf15hCdF/5n0YxXsCD4QppRIHxKmH61zdy+AiEA0oayPrIUczJxdt7lDNBj7Ty9m3mxkYgKWxVwGMbDP/U="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.6_1588462299159_0.3734411692494797"},"_hasShrinkwrap":false},"1.0.0-alpha.7":{"name":"@joist/component","version":"1.0.0-alpha.7","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.7"},"gitHead":"b478d7050fc333e587e75121a8eaab4af872d7ec","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.7","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-kYfpZdMFH7HiHpaT9Qddb3DgGotisw/zelDPhfwhWjKqhNF56/CS/ZHEnPwxZORJKVwsinntCEQRx1g7x0OWpQ==","shasum":"fd9dff72e73d94cc99689aa5bc31b498b295b90e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.7.tgz","fileCount":53,"unpackedSize":65102,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJergq/CRA9TVsSAnZWagAAPZMQAJqTQ6jlrsevaUeQtVCA\niExaDDTO1SKQ9mOnaZn8jP0YjJvIMr8ZXCohH0A4HAEXS8Uy/eH8EHI+TydX\nnIoSoRU1F59o7gNWnrL7JDU2gpLdfq7akNftKrWKSwQoC8y7oVVC1iSemmED\nKlyzQ1hbW8xCRBtAAvykDOXm3mBi2CzjGT95U5gOP4P6Opo+NH3mXkPHBjDX\nZQEgqVU0PDh3rK94bYpY8HIJjhOlSdEHIsgNCv9MEL3HRAIAQ6f4wZ16aAGi\n3JLvyLVdSi10+/CUkT2JfKEtb3HdQohojXwdjNkMLITVumJD8ds0OBws2IbM\nlMMGGjp3yt3+sxBQkQVuZnHWg49D6uURpsdZArr76Sk8UaDnfg21FKqMANTE\nBKj+QJEeiHIN7ofeldqEx4AsjLZm4vlJJlJYqY1gSfj5MfeH25UnB9KPThBo\nmzd54ugqC4wxS3/Hk6K/uSMHeEcJc+xoUE+MLw3iRAe3b98j/8RmoRVqhavp\nuo3vfpuqjo5R0pLPcteVei9PT9fErRW8R4ZTBnqUo5aD5FLwwTUflK6D8pmd\nLqW6sCp0+3qZTU+n8YDCNJ8AMa3d5BcY8p+6PIc59okuXw74zi4aa27QTn1N\nu19BhP2+GQHxHwozH9Duy87qmIoJrkh8flfqeWAyIHGFVCqUYGrwgVtyrJQp\n+QU0\r\n=X0sG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDzeXeW2Kvg+D/WKMQ4K71QfUF2ZK2CvepwfLNQD6UsegIgJhOS0R+oXIcAHQl+PXL7VKApojSq57zFZLDiNWnXtfQ="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.7_1588464318656_0.7410909620416517"},"_hasShrinkwrap":false},"1.0.0-alpha.8":{"name":"@joist/component","version":"1.0.0-alpha.8","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.8"},"gitHead":"093cef94f5fe66998bc21af4afd6a7c814775439","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.8","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-+6zH2HHk4m+L96mjoMEuGroRmhtQHxPRTKgHOX5JUL53avg1jGgJpun1tUmqBaQypmuFws3d4kYfMrBgQKwIHA==","shasum":"0155eebd14c41dc1d2c88a3a9b5e82bf912bb455","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.8.tgz","fileCount":53,"unpackedSize":65102,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJerhnkCRA9TVsSAnZWagAA+t4QAIfvmTY3wJrA0AqX8xCa\nkp60CImjh2t1UvlIGL51FGmG2uBwGxVIvVbohNJjtdOrYPULB8+18yAENoIY\nj0m04Rlz5Avb49BH83h/XSW40+59ce4YSSuJU7C/BKPC5ImgGuQGsIcQdonE\ny2RVdpNBSrQl9Ur7JT0IPnyXdY8kX3z4IVw7PkcsYcaHdRH0Mu3a4L3Wh+al\nt9w8M/psv3uY/q6gWwiVxf/5hw9U4zZD5pMwrUAYgS2kAU68irpt0MBFn9VC\n+tVuTpvF0SRF5F4qZ4of8okO+4bt9rdDvX7GlfxqXNJVM0kmxnYk9z/HPoI4\nbbdy7o4VRDu6AjU0agEDlgFWntPoo9CJLNNqiAGLjPj16MdfgjVqKXis5ZFw\n7zgGdInUmAlFQ+ljtsnS5C9DIdqmZq6TKzi6BBuQ1Z3QSKm+ECMzhHxqQv7e\ngzYiGMNa+2y83yWgvde1AD6rrMzQm83s6MGcN8a9/F1YMqlWKAuwB9EJbzSi\neOpeYdQzRu98wnwJ5o6p/dY1mc0xoz5W6DwBtlbdvBg9RdzuItv7RyKpHjKz\nX5e8Ann2cbXz3c/Q3z3HJAnjCVuXDgG1tcglELdr/mnolG9eH+cynQSull3V\n7g6i6hy4HPyHuPGTbTyKSAgbjKqk3zFIrwzbv65WTATsKpOmHXIKp6ACXAsO\nY0UJ\r\n=4amm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC4QsOeR0MHNbV3ZPh3E5U6PYhfLk6IdIjpNDS5GASFIwIhAIF4cWpzEelzqpMc3IZ20NH9nDoaKmWJGi7MPlJH/jMe"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.8_1588468196420_0.7706820050902121"},"_hasShrinkwrap":false},"1.0.0-alpha.9":{"name":"@joist/component","version":"1.0.0-alpha.9","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.9"},"gitHead":"5168927796cbcfa9f6406c033f316a39be910a9f","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.9","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-LJipM2sjmOkeUu1rjx/MXkjTMM8HUzANF2vAlvZAJ39tiFH23v/9Wu2q1bg4bFpgRPsKmUJlc37IJ7N06GqCuw==","shasum":"ffe16efa50e786b66fbf708f6b5ead48d87246ed","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.9.tgz","fileCount":53,"unpackedSize":65118,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJerkwgCRA9TVsSAnZWagAA9awP/3iQ9+lzHLw+0OK6brav\nWAf2xUw8X5Vub1fjUy0XsPQKsm6opYp0ncNj9Vorieo5mo8gkYN7rxURxyfg\nOFog50w7uEda8IbQxdC2R/8gbtySjil9a3tyBkTQizyP8EqFe+8QeyOSqPnN\n670q3UW6QAih3FGb8rBlIsjjExxrWRXLnBWgoBBtXiv2drVV246Bi6hxrElW\nlzDToFU3X7QYXoNYFhYzkvJ+/39beJF2Nw+5cvLLHFwEgn1CWlDdMAnxCZEv\nCHlDbnKKg4TECc1oBG1LsmnfMOhIYRLkTUIx0gptYkH4DR5TZ8086LkBm2R7\nqjmOdhHeRuyiZzeSB25il51+dVoBbXEkuYnGHhzYjKi1xs2ynSQ/+WBZK4zy\n8CHFUegcvmMavkAr7BvyMsIQQ5p/HFwvnF0/p3VzfzieF5VogWvJkW5GH9d9\nyBMxacdQ8EZRl+uhScGsdt8kK8oRE8psn3NYN8R79d7uLWfD/c9bCAYBPVoi\nZt1lOU/4k0iTt8f9b6WbSRms9OsktYdB298grgGWoRuRVuSy6p4Q8vzF7p22\nx+2OglI+PTYjnfPd0UtPbuJyxRkVB6Ba1Q8BTFLEPOu6eKTLx/oiorKhMSMf\nhmTI91Con8lJrUdgdtfgafyLdmWO/1Tewqqhxi3FaZNH9hs3MoZipK+SdZLZ\nR8Ms\r\n=m5kv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBph5ljeoUc1ZqohoBTPIQPNgmYDTuJ5+YPEWIL/vaNaAiBUL1omv/hCFHIgAEMG09pk/RyqWmyA169ODqS8rtcWqQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.9_1588481055862_0.9370954805198535"},"_hasShrinkwrap":false},"1.0.0-alpha.10":{"name":"@joist/component","version":"1.0.0-alpha.10","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.10"},"gitHead":"e8e04c1d90615157b2c7e7465b9f6fcb90a31019","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.10","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-GOiwHBaLYK7tsP7hgzTqlc40BGG9F8tlbGPhnMphYR5QDftBJgw7SWOsaVsB161dCRbphRJpyhX0zdjNVJRWTw==","shasum":"760ee2e8c4545213ab33926e21b9046fa139e515","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.10.tgz","fileCount":39,"unpackedSize":57776,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJetsm5CRA9TVsSAnZWagAAhsQP/R8Q1Wl5LEWQZt+bZj1B\n5dcC+pEzXi+hf1EvNDH17SwxC78TYwsz9bW4z49uQy9yLf5UiaHIKB4qyUe4\nDP8QreVTK1AZNF/+HvS8akdJyHDOoCJZhVtb/yXpksiGr5pDIMGjeAFHbyq5\nrhoOgdGC861x7cVx4ZcqeL7wGU0Km+oTg6Pui3l1LcRNa4MD61tOA9gh2tcd\nCRJUwDsxpaLjuzNxW8F2JlP9mzCps/uI0wAjFfxx5UIH8brHGfROTcgMcf/Y\nF3nN/qlBWmoYeMmB3A1qOKawWkMK1BBYQYaH+h3UU7BkFhF4IIIqYIeZbUW1\nCBgyJtfd8JLq2zFnzwFZEpsuJs9yjkiXZF3+BMm9hrJKGB0ogRQOec9NZEO4\nXI3P722BCqfX3rK6x1PkwJiBzedMp8luk1Hvg+spj+5bUu2QyioMndZbwyix\nb7xgegRrEMU9jNMtbM28hSXoAuF1OhyHiErKYsfj1PxNFUC8jMDWfLZVKVJI\nfFWKQA4bbotLdcXb+/rBY5Brg4+BF7WLZVBh9jOhEiOowG4hTQyOE+EHfoXf\nUiAlqFi6V/X74QEROapVCar7yzwK3VX1TH0/e9c1kvIRktgeL4mV60M3ldhR\nEt5puNCSE2UQ9pkqMnYD55UIuHpf4i/WCe87rUJXWcBASJcNPrnJAnvF5OKp\n37yR\r\n=+YQz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH/RO/alhsP56lOV2CLNGnX7QXCHRJgQcj3sxN1RH3IwAiEAnOg6HbGYfDMQ9zA3ZphyvzZSmq49jP77I/bYYuB7FVs="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.10_1589037496968_0.11836299685420215"},"_hasShrinkwrap":false},"1.0.0-alpha.11":{"name":"@joist/component","version":"1.0.0-alpha.11","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.11"},"gitHead":"98ee3ea63570b694596778c145ed9aae35f41d16","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.11","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-cAmTJ5hXjYxBpKnAYOpUPSB6pq0sTq+pvhd758Y2E95Q8aQ0LQg0tu0KTMBnjpT5ghYSEJ2TttyuK8CsXwrmig==","shasum":"7882c22e954766f6bdfb86c8df94756ffa02c73d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.11.tgz","fileCount":40,"unpackedSize":57881,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJetso7CRA9TVsSAnZWagAA/7UQAIA2lWx9ErVdLvqfLVtb\nVonkH1Glv0dYtuFAXtPSNkTA0uNG3Yjs2YrgL6ohQ2JWxmPQE2IHlS1Xtf38\n8xRnrVLAWU6zQHDEPOw7Lbi2uSkwFRdpK0UsqJ1FVbN97mskquTppw5Em/H4\nPblpyfGPfJ+2YqJM/2QDqC1nj0X1cMYCd2tkLe/TUqgwoGen7O1hqS010/SZ\nJz9cdVwH3FS03ucZHnlj+FMMUpyYrjwZw1r8PGP1mwAngaOjjFJCcwqHp+7X\nvpr8PCbtY9+rfazPtwT6mvc8WELfumbpnSLfKWEgAjRDtOpCUAUdRk70PDM8\nmiJJcxGy2PEL4yejcNScEgCFAAi3ZZCqxdNaD6Hnb2FpPXB47nIBWtMQr6Ri\nLncl3JNiOqhf12lWPNXNU8ZF3atb+G0oMqwrOcZi5wLSOJODLE3TIWpU21AC\naFPnBBIb4idhfuQvKbDC8bW+MkTJV2BEUobm+vRrbXuC2Yrcme8C7JHYkwza\nhDqa2eea2RqlKQ+jD3gXtvO1zYV28qrKvJ9ujR8IT7TBrxmyfwKfSYp49vgT\nqLLyY9JOnRIG5gnlqy7bXSPBA3LO4ZD1DX/cDWbJk4Fey27WLZltkL1jLqkT\nKqkOCn/EwZ5q6DIkpedCO8KWuXU6LxxmP+QpnJLigKhQ2CpnYj8vbiF1E4jC\n6aOf\r\n=xetZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDxbAp1keaNVVaVRaGa4UuJO0RMx9Hr+njKq4ZEjzlelgIhAIrF3Ewp1v/BLZVOShUnzqI19uDWSgJ6IcFHyzfGYLtq"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.11_1589037627523_0.09882595956568485"},"_hasShrinkwrap":false},"1.0.0-alpha.12":{"name":"@joist/component","version":"1.0.0-alpha.12","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.12"},"gitHead":"1437eafe18f4765b9a0cc5b56eb3008b2c6a194d","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.12","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-/qtWS+ENfkIGI8WtAQ/gF+z4V5/2asf06AHjcXvxUTpPRJgES+F23xH1rhchfZKnj3t7pFibI0IUcbTQcelBYQ==","shasum":"cd596c4f8ab34e01d9c187064425f6f45fe5ace5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.12.tgz","fileCount":41,"unpackedSize":57928,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJetsrFCRA9TVsSAnZWagAAkWAP/RA3KD9rBihwGBDSRRk2\n9ol8zcwHJ5SRDDXPyXx0/rm1ht969ociMcnt+jjVyPX3Pjd4TC2hiV/Jh4Hr\nVpKnB7sUoKUIFdXNSSMFagxi2E2HZDYe5NQBQLIwFWCmw6RW/GtNdjUEtTXT\na++ECUFl4xTXiyZ9hiYdjBxZYdVFMlZK+QlMOlOFXxOsU4MMLyZvloDec46Q\nRnwk4l6V7OCyOv42AusKFhVcEHZbOt5NQDT+k5QcZscqh/5BBURQtLbG2jWZ\nrA+8mXSQE66LxZaZj7aO0mQtai/dlMC2WyPqIBe40+ADHBII6cjP2HA+nZS0\nlWB1DnoEvwU5ROClN+ks+syMoT/uuDdy0+ycGLDSTM8ufqJS42Vh7aGlXcQv\nM0TyEJl20KER+zisG1tB4e4o6pyv2te53HeV4OobGeTCEABt/hjKfkXISGeg\nSysQ4xv5O4gx+qFvibuaElbjA1Iz35jn6Yn1KusiNjJFIkeXmQl2cstWQDgA\nUo0K3pw64vrETizuJIXsIHMQKrhG+tN7aLMmMnaDhSxfBz52m3lZFDBHfLhp\nXw7eLw57Af8YPLv3K21shG3yT1RY1V381mJEccW9n2h/L/zzbjrS2tcbFc8Y\ncAAPkxTL9sHI3YqoaukMly5zC//XvQQCa1xqy8Ce6JZutXuGBg8W8QpEJ+tm\nU8CQ\r\n=GWam\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDU1y/9qlghAbn+Yjn2S3QvNb/1xS9+YYUFgFehXUj/DAiBPyD47sEBoctQmIqHrZEXcEyFor7ZEDlfkydF0950apA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.12_1589037765139_0.6077564720320554"},"_hasShrinkwrap":false},"1.0.0-alpha.13":{"name":"@joist/component","version":"1.0.0-alpha.13","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.13"},"gitHead":"3f9bb90437a1d81f668e0fffc5d7a6a273921bd8","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.13","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-qWYcC63iqAAh3U8/Hcewr+rFBXaoQzRvyWwbCzi4voo+MO0w2hEETXgbaR5Lb/pjGp/9R76R5czaLD3Cd8+UJg==","shasum":"84e51d84731986ce5bbb22acc025c2dca00fc8f0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.13.tgz","fileCount":41,"unpackedSize":58737,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJets2qCRA9TVsSAnZWagAATLMP/i75e8BEYJtdzlY9Xq9E\nCd0yYXJlqnKJOtGHico9dYGEEL8S8pbSv7W7+liOtpA7uu5CkwxQILzlA4c6\n98ZljMjCc3GRUggZtfxuMI9EMP5AO+sX2VztTKBd/gH613bQh6scoVaB0KeY\nzDTJCICcuSC+yFhCynMQ4qvFSIECHDq3681C5INPOzBP73EhBTKDYtj97kiy\n6HKf/utq7Hme529V8wBAJQDa3wvIOMls25x35TxLAQqEtRAwozvQv6jW4Irq\nnyxt6Z2T9A3CwjZTOnZrRTA9faG0GCfQlJJBVh4mlQv3NgUIZkOcv2ZmXZBx\nP43cHzdVTJR3vkDYVdvr3t6GW4K2eKueBKmAgbeCosg6tuwkG7NM533cZWEd\nGJ7nhJXOPUPTfiOAO/At6DOBXio1wcXlLbZ6q5jSHNV5wjCbvQL71hyso56V\nSFX/1U9tp6UxxL3CFyLuByCy8xqhB+UMjFjp/sFJ3Eg7DGmCP4tTmbeIIiKj\nZHuIsX9/Dhl+7RQjV5+Gqya4Xr0gu+JdV9EO21zFTsFIYSgjM8eAofWM+wG4\nOQHXYLO7chfRn70KfW2lpog1NTR6kJRwGn6CGbMCdVJfY2OUcxqEwFO1menM\nTbaOSDqsXBmCPaq9l9mH9vbntlT0bqUInwdwzmg/PuopJUBSlRFGtkFCQc6V\nq4hU\r\n=rsnr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAz12sbhK496bizKzINXVlaG9neA1+IAwHij32wYN8cGAiEAny0O01piHZher3V1YfNt0rQwQujaByA6Iv4rysONCfI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.13_1589038506074_0.143964538951455"},"_hasShrinkwrap":false},"1.0.0-alpha.14":{"name":"@joist/component","version":"1.0.0-alpha.14","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.14"},"gitHead":"27c0e897da9e5f3649b42159e057169b64ef3a21","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.14","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.20.2/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-Ely5e0MqIfnw/q8C7qe7p1y5fbEoyxN4+3wyKzQGWnRFZDphGuZuY9/stV/dxKgJaC4ddD+kiktRtyitfI/4Bw==","shasum":"ffa2284c414712f9b4f4db3fbc15dab2d012a714","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.14.tgz","fileCount":41,"unpackedSize":58737,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJetuFJCRA9TVsSAnZWagAAYQAP/0Vi9KnemaJjS2vglrNk\n3nIF3YX3Yjmx1ZMrQh9QIUlqxFna05u1C9VZhz8cvKffLU7d1bIIP8ml9Zai\nEhRcO6Vv5Wgfl1jM/mgcPBib1XQ+lrILjdyp4962kU+b10/ZENndnwXGtGRq\nT1g9PFNrTQzWWl+98UI2z4FyjdWTG0zGDKcNpO2AYPhltExM80gcDEVtpD2f\nasFNMzHGBsgRxEh10V4MTOflaxgCdmYMBf7pUVBJilHfYEFiFwiq3xZBKzJ3\nTOBbxI1Xv5bJ/NJh0QQXNzF9899KtUt4Sr2im4UG54BiNaBaIDib12P9RZoT\na0muiQ+HcnWZJjRS+4G44I5wNTBCUfUJO6HPiE8kTpILIdhq32OYqqwuS6kw\nnXq2fK/WdUAn2wDA+FAEk29cGiI16alp2MhoFDIfvoG8FEo4TDS2fG92Lbr2\n32rHwnNq7Wxt2DwlZrXK2Tc8EbRv/1nzlwdY6U+ztXlzCxxfdZ0f8g0SZpEE\nQw/7yL1WMK8w0ev0WZgCH7pGtVbyOJVY4Md2BVnaLv1AFuOuK3Hvm0lI4eaS\nPErQzXwMy3BZh651k3IJnfPRujfXNT9xNeu8tX3IYC7uRHShSa/w+BK6zH6M\ncHggzicV/mrrfiV+E3gI2jEVqOS8RkMxz8gK6dTuT0bZriAP9xZHj2iEhGw+\nsBnw\r\n=vbEl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDsbEZtXu/Be0lS1YKzyn4Hps65f0O0xURaFdefKg8BgAiB3eyewPITguQY5Hhen5lT8PQLFafpfmGWghedD+HwjlA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.14_1589043529513_0.30511013723333646"},"_hasShrinkwrap":false},"1.0.0-alpha.15":{"name":"@joist/component","version":"1.0.0-alpha.15","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.15"},"gitHead":"25684392a8efe1290bf40f21c77b22d8fc743cde","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.15","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.21.0/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-EtZTr/VmwrSGFjWxZ2/CSH47jvTBuixGF98jvmGk0VB37I9xAv0UdM9FFEAxz+73XEe4K5TsVtGXAkbPd3QhTg==","shasum":"d6df119636eaea27b1ee0ad882493b1362e256d0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.15.tgz","fileCount":41,"unpackedSize":58885,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyD0UCRA9TVsSAnZWagAArLUP/0UhrmZk4tfVz3SDpmYH\nirbrowvX4KNkB3h5D1lj6fKtrsI75FgeHPCjBvMGXQcxvbsV5jXgj18zvqYh\n4+AsKF6OgtJdl/cbiibTbfgaRADiz8wkUylySjZvItqzwDlWnbGVjeNq/hX0\nTkiN2Ngm0jM7S/bXe2ZsZXZBrm85y0kIU8zBHTshxt0kv70RZgqIvgAHG3oy\nCf7CBcotQqSEd9+d3wO5Gsw82cCtvyJjTVR2oBjtQEPdcfiTLCK0mHcogHkD\nz9kZg3E9cxNRjvd2k822hHis7jZyI1VjpLHUI+UiLajyzp9bcoq1r5V1ZwtF\nqWdCeoydEWOrnKIskuFCnTMskd9kIhSk1mxcE8TSboZsGzg8mhd6wFLX5VA4\nWbKt/x4V/KRKUrvFzMidYQP6bGByQosZdENg0eNvuUukj2iZWxKJGwhJJXrZ\nZ/zKqdimCrVlpmP7J+yq9c7sQblbN6FgWA4yYPQwvEVfMfyd6bsQYWycZNSO\nM/ImlEbzrtC1hL3fioIZYF8AuPjiRA+pfXx6GgO4WY7RIAHpX9ItVSPAwFuY\nwuS9V1I7AN1uPa/w+AAHyN3m/Vz1OWomCrNn+Z4YLvqAIX3t/UNkc9vGgiHh\nAKtGBmLJ9hHr9CecBG1WJUP7oOdaDvf1dpVsh3L0Sz58QmOKCNHp2/asezkt\n/xGk\r\n=pE3f\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDdwsUDlFvr/uQPPQ0/4cW/n/7io02r8i0Br2lxa6+j0gIhAMEyr1M1derBzwcJiIFCCA5C/XI/JWAIsO1Xel3sDYwx"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.15_1590181140068_0.1137324257954675"},"_hasShrinkwrap":false},"1.0.0-alpha.16":{"name":"@joist/component","version":"1.0.0-alpha.16","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.16"},"gitHead":"07dd7d8e368ec14ec6cfc4fc351ec074f802e6fa","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.16","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.21.0/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-tvZ5eEMFe/wKREIzw7/JgpKHoww5ynaXLxfMBqmPEjXd+L6282x46e1bNpAKUCfLLuUfRgJCs7KRl1sbatGgxg==","shasum":"b81649d56a6a39f0e4bc01c5639b0a8e056ec686","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.16.tgz","fileCount":41,"unpackedSize":58885,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeyKNqCRA9TVsSAnZWagAALwcQAJQTaPP71VcaY7DnzKd+\n64rMwTtL+DhWrNm//Mmf+OIrutG/VceTaSQzftKb2eHSeXfnJL1EkqCjJDMl\ndtDs+F9I6pJWQ1aefBc1EpwV40tzpvPJnDuXmECmtfRx1Cx43oH4UJsrysMU\nYUT9Nw/CSkocu8AfTtpDzugawI73qdiv3DjpBpNu4ARTm9R3lvc7JndrjVvY\nI5qVSCARgLzQqzWT8niMjWa3QK7p2qg7J6Seo2eUz7RRty2io3CML2uS5kcn\n+WPcN9Jg28XXrXCIBrHJbbv5i4/oh0SHFTU5c8MxcXQRlGskmtcPLrRbuk+d\ncnuLZEyHT/tFjsa67eQKh5GFFGjBlSpVFWEM1pEBk9EULprZTFo9K+vtmHvr\nJlt1BgbmSK7815H094tZCq7/CdVHy0IMIUprTEqeO2QIaq5d80mqdDALpX6G\nN/DBhxtP9vmpRjbHzZyA1QjwXTYTKKBxddTnE+vzU63EPJ3lg7DczXyeIbcv\n90SjDDun5mKl6ZcmQxEVudNKBIr+rcoEzV8pcv4XbORMK+6fcbYRI8OCaZSQ\nn4xJ4XpZNe9VOfiMZdkIG6uSCSvKEb/seUUj+m58u1pD7FkgqcQNFiIAnulQ\nAmcnRoQj94beSq6nsiFJOd570VIAir3mPIk3NDIN2Ll1S19CHFaU0dhzG1WO\nx9su\r\n=joU+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDIMEnM7Vno3WY8qkvNTCrqWQYZcb1I2PW6Gc+8yfwDwAIgCE83eXqVgMmmIy34PmIdh3fPrqyrpPQs351ZkeLw2gw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.16_1590207338437_0.05477804391582919"},"_hasShrinkwrap":false},"1.0.0-alpha.17":{"name":"@joist/component","version":"1.0.0-alpha.17","main":"target/public_api.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.17"},"gitHead":"7626cbcf9735ba75162773d50dcdc7fea349f760","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.17","_nodeVersion":"13.9.0","_npmVersion":"lerna/3.21.0/node@v13.9.0+x64 (darwin)","dist":{"integrity":"sha512-0kCsn83gCPUMQCrGuPSmpyIFcMWEulC0mJt5G9hzuNXqQr4fkgTyj/MfU0h5vOxQDb7Kk2nlG8p3FOEKXmEZmw==","shasum":"29aff77fd8ceba0e3457f406adc2935504180c7c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.17.tgz","fileCount":41,"unpackedSize":58462,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJezn7bCRA9TVsSAnZWagAAHpAP/1xC4Ohkb5uaM5CpKUUI\nRtSy9v9VLqASHiImB0gDksLypkiTRroKv9LhYZkR/BGQ0SZ7SdIccDnmuHXF\nYTHVG9msmS/Xu6IWwpHLcG53JvKphkORHJVqi2x76+fFe8SzUmGfEYqts58W\nV5c7fHvMT+FYD0RXnkayVDAZTTZuFNjHQTCpOh4r0iwJb3hd5izhvJFMSpV4\n9qbhOEGVFNEPqsVB+kSlgyHeI3zIoCN8+D4/MvOJnsp6ZF/r59MV44rBiPU4\ncO/b+uj94CgCXVzQ1BECzw+LKoJfdT86pVLzdzgK9wMuXRMS7ghNoN7VUQgP\nN6FdTuxAb1mXifSe9IcCfVFPegI1HYbw/xkBNc/7nxxeYRyKR8XMGL1KFcrT\n2tlTMCuqZhj2ZLwIrd2e0T32vssKEF8O4MNDf3bUw9IIPs5kGI/q9LawdddS\nJH+tPokEf1w/I6OSYuXFc8LiS6TlWNCZRaU/bhYTsYSZew8ytLdRpM4M9iK/\n6TtV62gjZ6IYnHn1oJVrP7ejtx+zm4nDi6jSbIktLIdiYLRmjKj7nWYlD9dn\nIl8Yb3OJW4Sdfn+tw5OpClfuvcPs/aBNdsATWnARjVoJKnmg5wY4+9BVFtot\nJ0ofS8m6+mvfRSPE0d8w3oF8IPqLhZ14Gsgkdmq+defIMW8YJoKu1HjAzN8n\n39bV\r\n=1TqI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCxQKg/UPtu3gRLrBqyoH3B5JKxx5tprtaUtijy+tMBWgIgeGVhvIMDpk1DIwlB4t08/xxcM/xjI6adH2Hl2prcAQ4="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.17_1590591195552_0.8484329775236914"},"_hasShrinkwrap":false},"1.0.0-alpha.19":{"name":"@joist/component","version":"1.0.0-alpha.19","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.19"},"gitHead":"d6d499c4e6602883f4e2c42e5e5c959d254b6735","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.19","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-2wwP7G7zC3b8aqY8+BeCqpwKGOox6dc7QrG7bA+qZYys6/HfuDBZtW3OngiL59EQRDUSWmZy7utyJZkIMXf3qg==","shasum":"54cd655ceecb798e9f66513ceb62352340adc036","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.19.tgz","fileCount":52,"unpackedSize":64392,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfGGmACRA9TVsSAnZWagAA/IgQAKEl4aTO96SZy7aU+UdX\nXn7IigyKDshYGkZv60GUVM0we+j3HVKmURTanVU6V7IUnixh2bIG/JzV+sk3\n5nexbEdHfMA9q5rNu/ISzKiusCBq7WjtX9latiPPMa/us25CPPImB9Ull8bc\n4oeZm+JTTQXhoeZbTn3v6zbcsnigvEz18dwFc3ytazV0fzJpNxvVEzkvMkAf\n+q0I21l52D8S5nkhE8QRvbvjdzYNXk4uIgJmz0J4fCXEaHBR3i3uJFsYHsjO\nfqAJc4uf1CPaoF1RWkHPrxagfmu11PYymAgFURBwJcCVdr4wL3+sG08xOJy9\n0PVWgEM8Uqm50Z23DpJluaWAOCzaRxpXkcta9HFoWvdLJasiq8ZzYwVzFHVV\na6QJpPn4rwtmgWQJwu0q9SUrnoSmusK/uDn+ff2f4g38LMKhfJyWMAFeHK2H\nS3/rkB1u9FKNpYKKg1mlFyJoPODsCU9Xx3fnIwzHL5joeh+EUdzhY7vlBI61\nXej2tKaD7zT1upkePF9RZnnoeLtxf5tLzq/NFI72+VBj5AeMuWkFBRwfwnG/\nY8gOl7NH0CSKA4U/8timQSWeBrlFxXDDxJEV27wiyBPE+CYoXuZPPJ86LRau\nUehpB5YkGwvyySjiE8hFzLyOGSt8SaWr+12qVmbL4jSb5vntS4X8ssXe0mry\noW0F\r\n=CXHp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBg5YFSce32qA0kfYrEp1dWe7a6VO2eBYwvhsAWDvIk4AiB1DZd6euvSpoa0os6ud3vNmmL69WvMM7E98e+e2Zz/kA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.19_1595435392549_0.2642358971934473"},"_hasShrinkwrap":false},"1.0.0-alpha.20":{"name":"@joist/component","version":"1.0.0-alpha.20","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.20"},"gitHead":"4abf850114072b565a60b2e4008f81b437aecf0e","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.20","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-wZqMiEgbQkRxkz6ROQt8j1M14ZjilKKE7jhk5FFiDkzHZj8ShqbSA0sWH5OyJ5l3gHCSwD0UDA5BI/xdlS1uvQ==","shasum":"5666f384f234756d3948bf46e3f7f54107e80d38","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.20.tgz","fileCount":53,"unpackedSize":64382,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfGaW4CRA9TVsSAnZWagAAQBkQAKRm4ZPyy9J3T7Q/oBQW\nMpZpivkq1vuzFVjw6r7h3urCJiBiExPQp1Xk/mdZASHlM/U6xpwl1+d485IC\nMW4OJ7Zj869fP9X2Pu5ydSmpc3/SC/p0D4vXkPfzVAq5+TA8+EXXDosWJtlp\nsF5xYedgCM+d100xo4lxHAxSGeDGPJQMvm/ZI5XYExwmpOAqyK+0R+FZAveb\nwqMUPLdac+AmDrxy5ZsYCQOda9BL4hr30evpiXMAGmDyX5usJnA49mZki526\nE+CYKk1e366gOkxGP8TNESdRaxRaQBOyrsxFiujbFYoV5VsCQmZzIE4GksIp\neEH8ltzrWIxGUTV8Wtg9r4C7Ppp6pd8UhQWDkWWwm+JQzUyZE4+Qc0KR5hzy\nBgfpyAT041Ib3YVoTAHC8uDJqJ9aAV118w45wppDoVND9E6TZzadSB1Gsd3f\npz3344mzR+1a2HU+BZeCr6gG7bBlqjbm8tpRPmo+QnU8BeTjoWl0T7MEQ0xY\nbdoQbRjEPRjGMUomSLeMq0BDLwiY9Eu3Ogmqntf58Xj5mbSwx0yxxJnfXlol\noKmpdNyHUndinJBFc0htu6JvR8nLIrINlwbxoNsH2vK3qeKI0BL+DYEkCc+k\ncNpIQ4Q0/tP8ucrwhIbLx7+Nv/yvro2LuaqpQP3bCaEgEoi0bmdTiWl9SotW\nvTQa\r\n=+8ED\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCk87FB1TT/IvwUNaNFvgfIMECETS3c0roOhcr1Rw2LvgIgL+L3jWJYtsFOzImrBOh28djolzOm0WhYqq/G3UdmM2Q="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.20_1595516343768_0.6657356998259831"},"_hasShrinkwrap":false},"1.0.0-alpha.21":{"name":"@joist/component","version":"1.0.0-alpha.21","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.21"},"gitHead":"da3d8d47ab2729194657b9a2e233bc1566bc2e60","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.21","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-0ovf9xCT0tVbPyMZg73k1HspePkmqsXdyxCa0WnvqLy2UKGJ71NN0JOP/pJgvYmfUW10kT1ytFyWW8EOWAhpnw==","shasum":"18dcf62976bb461117b3ea6da15ba0d1c51751e6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.21.tgz","fileCount":53,"unpackedSize":65767,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfGtj+CRA9TVsSAnZWagAAfEkP/Re+yuO4S9YfeHpUTd7g\n+yjzI1wE+uRJFbUNW468vEJQuOW6Mu6gWGgLqJArydYUugaennL7YckfqAfG\ns2oMc/D3yT0MWRTy5ZX5Str3vIVugL0SBJXLnhgwsZPSv7TnGr9St+dI9ONa\nVX+YxyqpIuFePJA22/yppWe7ZpTR4Q9vITRvObLFE1IsP/tz4w0B5+BOkxMe\nhqvzMQrqsZCO/6nhBNd2rMoCatIOSIzziC9q8fMA4o9gQu3GPbkwn7m9TPKM\nS4ROQ8UpWqw0HMdSaWWGW4lLf/rlrDlkBUpAH6Gqic+MEMUJ2NiqvCuu28Ch\n8k+/72lHQmBLfwcOrfWIWSOKyul39Dpy26inwQJMf/Y0YaqSIusmZg/yV4nP\nSA26Jg3JqE31kiugI6H7Ee/ngaVlBceHU6GZVKvGVbTrNJvG/7P8JhMuVBo0\ndj9mqBYSlyD4rjHQ1hQrWdslzjAprfzHpyAJ5Rf54il4z8JLRSpTe514nCFY\nj6sASDZVrW2SDK+99SLszkBkMDYpSjCJXRU/hk5LWVBWHBP72pYTLBHeR2e7\nUQYawy8lOV6G3BHVkI4/erldyiIkKvvCGpEFxBZJ2JUhVR50Og44F9cexSLW\nZVFbmdCmy31Wg6BfDw2ZRhb1WEeoiF57AJLtGzBiTfbFdn2y2ssNcWX6KBuX\nFDm6\r\n=wGaZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCgATRxJKcqtuhJlJfGkD4IsesRb73rAhtmLI3cG8wFygIgURmcPQQ63YjwksuiSNTVTUImabSvLEPcd8Vu2Z4LlU4="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.21_1595594992174_0.4032173611225709"},"_hasShrinkwrap":false},"1.0.0-alpha.22":{"name":"@joist/component","version":"1.0.0-alpha.22","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.22"},"gitHead":"50ac670d1b8eaf5003f9de0fb17b7173d65651d8","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.22","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-JnAFubQ2Vh/34XQF7+b/zTdJk1gOMkHYkCEgZuW2hWW0gtOUqrDJhGWtsfjA/7PO5vMGic5XZ0+v3T5n3JTZpQ==","shasum":"1f48a115b16ddcd561af65a7ff6ba3e992c16930","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.22.tgz","fileCount":35,"unpackedSize":27478,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfGv7YCRA9TVsSAnZWagAAkGQQAJijSsrM+81QTV6QdRB6\nr1tm0sm0x6hz7wbZW5+R27xsLxymVlZeSSc8AYCVeJ8kM8Qe04cLZgBgKGL/\n4SPwPxai5MK7KAxthLgfef3Pp5dlEd1/S5YlPAp86RguaAtKU28D8sIxWmY6\n8X03fC3OgntG4BXi54ETXLV6Dxshz+3EFk8Omko0WJLjqTiSAvMDHr2Kezk+\nQHt0qPZUwGtCPuGcA3CKyFYlhuSs8mYFAPYQyRmp8myZjYA26vM3M/k8zJDz\nCaXEBKpVuINf5CktDFXl1KLw2NF423mfelUtxRf5WP//x5euJfTwDbkvbzo1\nUtO5uaHN3SJe603uKKX++KO+U22LchymTGU0/d4X4enOGOSrjtDPU4BPI4AH\nIvglqwHpW4UmK4E6wbit2W6rfLHaXbL++xxuQvF2C2SjRVrZDcO6sz1rTZY5\nDktjCOIVQ3as6gVSiNTmtRipDSyZvtKdXjC/4oqqdrRChEJsX4m+wIkv8vWL\nT1DYY2g/oQdII+bxCSvtNhpIECezbrkArCl4ZBnFDrJe7ISPAkahm1uu5xOu\naDpXaUqXlkc0rMBHPHpsh1MzrreueBmlVQz0X1JCaySBjtTSTi9JwwDspT/Y\nb3vK9+T4gTGOwoVDYhHbXVuFjw0TNmZX178nUe8c+908ChasoGrJBjeXCvjy\nqUrk\r\n=7Los\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCm0GWL/ofkAH5sMPvRuqBZGeuX3gXQ0LPzM3X9zOlesgIgRmt+J+9+YiKYfYyIqmSIDGyQ0UAXpq5BlVy4YwciarY="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.22_1595604695553_0.9634786250939997"},"_hasShrinkwrap":false},"1.0.0-alpha.23":{"name":"@joist/component","version":"1.0.0-alpha.23","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.23"},"gitHead":"b0152fa635737e2fd0bdeeab3ac8af6a1310bd94","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.23","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-cqbRDsgqWrY9NRozfdlSrNG6dlXeHvPRe2O4mwzZJC7Px0u/xSEL2j/zHXLJCTODMAO+/4IHQTU/+cMtUfvfkA==","shasum":"b8ece11d2307ac0e987758b4e7a41f6de32a90bf","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.23.tgz","fileCount":39,"unpackedSize":30135,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfGyHdCRA9TVsSAnZWagAAx9oP/jZLnfGa4s1s/I8OX2Ad\nP+aHlyZr6pWreZUZzRNz9/ZD0WCm5lNj1urldUZ84nm9t4s1PQAtR3vTYVAM\n5YpVQBsYhuxLJREHeT6fOLc+xrzK9LehBN0fjt7ObKD1DFb9xN/yJHtKwqIm\ny3OIqO/v9claZBojJOVLHGKQeehSXhZEWEtklha8wDVhwHOhgRL9IdI9HG+k\nuxaeb3qSk0goQ9T4PwyL8peHRCe6kWaBcDn8am3qXvNKChUAJ9EZSk2bBVEU\n8DavzGPwPLjyVZ218VK3uZc7XKRXvfdnF+GNSYjLJGpW4La4P332cmjkGqlH\nM+dv8pMxY+77ef+FKdjVRjF6/Yz3Dc9Daptb+PHk/1xH0y4k6rLTUDjmKzsE\nA0ZaPCVBscTrYMUk1OHYVAO1/RgFiE6eeQ+1QyvHRR0FhBkZrUP2SbKUoAiH\ngHoBP4GWV9lCCUSisCatEP00ut9aJmEgzEbLivZNCcUPD250cthsQXVZ1Bxv\nahndvx+NtKSC80KYMh0usN10fq0rqxRQ4F3AOIh2GhuNxUmlXWw7kyfpnCP7\nSWcCn9J1aQ4cE85XXhxLV+kkfzd1RuD/DkDS8yoacGm55RSFMZC6x54OQABJ\n5FB3BPSYOK4GvXBWGbKMiSVrW+tAsdiInDoW39UGc9HvDkJ94KHum1nMpl8t\niYaU\r\n=VOsO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDf4IihG1Ne50FqdFojnc+0+aVSoVduJCn3EW0uiW9DRgIgGN0fjd+28lIH3OZrnnpMA4SEi9llq/rZ5Vfa/byC0Ls="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.23_1595613660846_0.8015691676160279"},"_hasShrinkwrap":false},"1.0.0-alpha.24":{"name":"@joist/component","version":"1.0.0-alpha.24","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.24"},"gitHead":"c9deb6b5acc694b3964dd1ca82ac4a9425717ee5","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.24","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-OBYv/l9vGoRC9ZQYRwU5VldRpJiUIgGsVnRjJ5+UKt/0DFdmHOPw2E5o24NjQzhHn9yVd+YHwPgZsWRSJy4LOQ==","shasum":"786c729d3a6d79a5e3f074c59ddcb348ce1d9178","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.24.tgz","fileCount":35,"unpackedSize":27911,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfG1BiCRA9TVsSAnZWagAAQ8MP/jGFD/1VM2GM/lmezODh\nwTLC41Zl6jHQCZN1AtZMRgGufJzTHSi+CnOEcigyiVXOWFVeqMAZ/NT7xhT6\nuwMjxwgcIhaXb2TncuAO06pgM+z2RM9JHmkrfiMoH+d7w2mGAwEFd1eTzOBD\nIjYNB/0dlRD79vBiLwwjC3duS8jzke3j47zi2BdllwX9lvGb0wkhCo3azm7W\ny11f3PUf4WSOZ4C5E2hJ9pM5RcOHKMTv3/Ul6i31XfUIWgpC3/GrpqQBpn0i\nXz9hpqz7eZamlmrVCz5E/U2sLlLxN9DykmGc1qlsRHCcNTzciDKanGcbSV9R\nyUWUudD6p2IVU/ipRWe3vgcTlNzO2oUwt11Stg1Qm4hFy7NA0PvXVEPt9nWe\nhC3rOG3EC+s+EtqC/qZkudLWkjokBewon0M/9zppElI1aYxBGubSsidSTYxw\ntDFS3XtPO/M4Wt53N6qelP3aC+cTpo0MkdWhkgyexrFgZBu/EpSKx3g+Dygu\n+preQqAcFaw2VlyFX/0POyMiBiJeIxVBBiXyLW19ys8OoB1QA0+0NoaP0fA/\nr7DHV+CH6IeofFsggv8JtmhLfoRZbpsiC5PC/MZngRGgBinhpDv76OyuIY/C\nFG5QUCj+mJ6qDR+1j+s0b8xJFJDcreJ56L/T7ceIFGPdPj31f8yyvvdVqLcM\nEYj+\r\n=2WBK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHKG5AVAVDeLsohr8mX3DGOjd9JY7ytbFvuKaU+5cZsIAiBuyKuM9jHzRwy7TSOnwmgIudJdcjXsjMNc58ZXEdDPxg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.24_1595625570031_0.5682917656774156"},"_hasShrinkwrap":false},"1.0.0-alpha.25":{"name":"@joist/component","version":"1.0.0-alpha.25","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.25"},"gitHead":"ef89a2b68d633ff0e8935ce00cd5cc1924f6bbd0","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.25","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-oqV6W9s7FGu2Fdo/KPHT2hHe2PS3/tty5+XslPMlgJ9JmUIcmHRKP07AXYg7wddqm8MBm0wOp0i0JVtpL8etxw==","shasum":"6895d133ddc498fe8edad724d11d745b0d7aa0b4","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.25.tgz","fileCount":35,"unpackedSize":27911,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfG4CeCRA9TVsSAnZWagAAfGAP+gK0Zcfv6M+vjeOIDNT2\nj0CmZ6SUjr90kVjX4C/Pq8IvGgCG6ACtQsUyAHllTqE4Gkj8zQI8gvUvi8gb\nkLipS4lsvyFxVVNXIapdsxv/Yx4/uenWb4N7LmXdIJ2auzsA3btNtkfn3X3y\n/EWUqPQwOkJBK5el6QE67Lx4dfLqvN0IXWTay3vtfiY/xq1eSQAkxgDDD7UJ\niWQKw+5djCUQ6W4dtVWmW9RaePK02kpiKMSR/fSRBPCOKGQ07Vz5KMtxDWhr\n9iQVIPq4yl0ChfVwP9Y6txMWdp8Umjt5DRxsLO2DVb+TnMt83p1Lya/huIbC\nk2fG3oBLUNuKlDooHs8ltv7hxE1ZJBK8QVfMl+EVa9gpkCYYg8PvrZs0WqUG\nrsM0jU2vJmVE4yKdtVnozlTmyLdgskcjUs0BRzWRcxmlLthdatMgFtrTZFJE\nl/dZ0E4aMORTPz7BknJvJhdNZby8KPYgFHKdLSMicJzbCFapFkCVj7CwcHI6\nRd+fysILAyGpt3QDyB9/kVB/8ERq0/mulgaN5F3J3/ggsXjgC3M/fZjQt3Tf\nkn8q09BmEbIeiuZisGt8Ez4tbf5cVweLpU/MtqppTtjQvhrHn5PwmobmMffS\nuO1SFvDke4PwsI40nSE2HwyHelYZJch4dtqislrnQOl9INAFXxwQ8fDzoXWM\n/et6\r\n=LiI9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC4nPzGKd5W8GcTr97Y+Av0Jwo4bPenhZGi8Mx4x2+XHgIgW6tau9ttsjEhmSjk2z2BQeKyaB2e236FRMYbLwaww1Y="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.25_1595637917964_0.005319619158592248"},"_hasShrinkwrap":false},"1.0.0-alpha.27":{"name":"@joist/component","version":"1.0.0-alpha.27","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.27"},"gitHead":"8130d4adea5a0614bb6ebd01480a05b96a858d71","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.27","_nodeVersion":"14.6.0","_npmVersion":"lerna/3.22.1/node@v14.6.0+x64 (linux)","dist":{"integrity":"sha512-pXHR/Y+VhgVKx9k1QrU6VXrfysVvPedidWupoy6XMjoFPBv5ALTOEOd9b2g/R8rN0yay6Me1LVcQZFcOVY17Eg==","shasum":"298b3d89a67670135ceb1ed645884504e9c288f5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.27.tgz","fileCount":38,"unpackedSize":29357,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHYW9CRA9TVsSAnZWagAAsjgP/A1Q7QRFdUU7otjc4zZV\n+Qk/T4i+K5T4OwAqHjSxprKoAk/jJGRaEcM9a/ddIZN+k1X/XGN/yWdv9Fxi\nvvepelGusN+VERyCIwmffNyMd7x0L1GgtG1zcv357TaaGVZxyXUYw8K48F6v\nQqJx+7RdC/lwTgZwhciXcmOfXg4Usm6Mj59+XvshkFLN9J9qkY/ZOPynodaJ\ns6tF4fJ7sEnmpcHqhz1/yasROCrtotl0iS/u3E+4CzFGWF5jV90OEN1GO+50\nPlaQ5s4ZbAXH1//NUeZTJQ8VP2bENIvBDhUnOaKSye9GN93CGHwmW3oJmhwZ\n54rkeLPoZSz7ngcsiN12UazliwUS15u4STORq6MRUSkmLNaBH+CHhD+kpjR9\ntkmRzkfSmOjDg4MtLqjlq1pAaFs7iIPbSfDuK1o0CRJK5MZceYeSWLjvMa6W\nCe8ZADaWJNrPM8dpuFIXPNdNwTVnamKW4LLMd4ZqhlHihtuc9/7POM5fmRi2\nlK1zVySKKbG6idnkIpDo38nA6F+lMGcxQcmHyWGoVIdqUEK44wqV3GFQMjTh\nwf8ycURT+5PYp5tqbtEiH0GtFlpoI+4ErWbaT04CWFoo6cYbh1K0Us7VTzSc\nPmxZsKnVvVnfdBFj+m7aJTMdzvaKad1IPEtsJRQ8MuYZAHRrZ5r1uuzoeeKA\njghz\r\n=sXjU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID1GvGvgH1j5BjKcUdlAifQs5vueuI3UC9TZvaB3550iAiEA3BekHZcEP8QaTIJ4yN8NcSOscpz5+mK9N+ordxtV01Y="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.27_1595770301100_0.2786118533153201"},"_hasShrinkwrap":false},"1.0.0-alpha.28":{"name":"@joist/component","version":"1.0.0-alpha.28","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.28"},"gitHead":"666914388b828559df495d2da575f56d61091847","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.28","_nodeVersion":"14.6.0","_npmVersion":"lerna/3.22.1/node@v14.6.0+x64 (linux)","dist":{"integrity":"sha512-SY+qm8hm62mr5VLGw5sX0t/tan/eEQrU3M3pX9CJFOQaS78hOVUN+8XZMIQ5NZqfpIgCK55X039QTNTu+zkTwQ==","shasum":"7685a01ed236a049a444809fddc3cc57bf0739b2","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.28.tgz","fileCount":38,"unpackedSize":29486,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHYe+CRA9TVsSAnZWagAA4jQQAICxBIZFchwGzID1ZCBP\nSKZvEsbHR5wfVGcsia5SYOkukk1fcZ42ekuxOsrVW0uJ/RyNHXNWwN63lgzQ\nM5tkBMnZ2rpq2JsK0csx4YNE5kAwSlSjZrOhqCZkxFoOiSOobiSi21vImUqS\nlnpH3qrp1XpqQsob4WuUoap3mp8NmSklhsyWbZUoCm5DztUL4WtbsQAFvb5c\ntIUC9ZUJ+VEMw17B1FfHOlfPmdVf9bhZyqFv1jSA1KJPjB7kaUzkNhrE0SIc\nLJx8S2LVwL5Uv4hp1ibWgjF2Lv7a8xUVeWMC9tHom1wZ+sYs7sDOV6hKTZFz\n9miT7pvjEUOrPF7Wathz79O9blUXgy9/3NMyPPZXbAtTKrk3JhwQSaUPpsLR\n0EL/AgaSyr/3POUG9IqBsipCX4DHjJ1KEtG3sy9Sl/y50NKpv0YoEYpbx5MJ\n4ciRaAsrQtF6Benf1/jneWyVsx/KByW9Fw1FT+CYn6Eto9LRG5QjH57QLux6\nu0eevCQ7Eyymghf2shC1kCnGN9tu9admk1I0jsqMHRNFIudQ5xNXIGfmUQs9\no0ER8oor6bGYH6MMzEbU7CA4UxSABa7dzBcSfB5HJnkxa1xINXzKgTk5tojZ\n3Bc7ocKOaQEeXXWoM2mEzDjK4J1Ft2MFTLEz7zMWn8SVwNerRzKg9muKRc8i\nNW2c\r\n=ThDk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGEDP1RKeWx+v4Kmxbe32AgrYukydfg+WVQOoCj+R9RXAiEAoTVpjur4JdEyjokNLiBBVF7ZMqIAxorFT7+DZfsZa+A="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.28_1595770814307_0.02063072740365568"},"_hasShrinkwrap":false},"1.0.0-alpha.29":{"name":"@joist/component","version":"1.0.0-alpha.29","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.29"},"gitHead":"e7448db4b5ed2daa6e264f9037cb1f2cd83525ae","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.29","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-oAVVHkUXBitNLQF52Yq6RKw/TSmUUU1zB4jDQlZYp/OZCWWfGEQZh1xRBtj6dzbqct4oZu+PkYuMTP8SP6h1cg==","shasum":"9c69bf677c933532bf0fc56139688b4fb32f8921","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.29.tgz","fileCount":41,"unpackedSize":31424,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHtw/CRA9TVsSAnZWagAAn4AP/3CxqEAW2G64Rk65cE6N\nLjY6jNW+nA17QgzW41PvJANqdvTC/xdANBDHCp06N8R9FtEMlLVC/W8h2K/r\nVjG7LxdL41WQUH1+541V9ED+EUTzjxdQroQX2XLeclt9bwLlU94oO1qArudq\nr1KP0GmrK1aDUoYS6JVA0yIKBHN5lju9zpt1YYm+Sal8xdurRjbOuocT3vIg\nBj15iblh4qtqdarDh32jANghqoIp46HGan4DSkQLPT4QUfMY8c7uVnMVIbW2\nv/9178faZN/yR1wB1K6B+AiG1925zAJfbgMv4Uil0/J0idaOrlkbCfNTy+Nd\neGuSSgHfm11Ms1PHdpnUTISAN4TWjNj1T4NOj0mHljnxNVXq/uy1cz+mRWST\nado8IOJg5yVOZPw38n7ChovKN5fidE0Wbo4HYGc3nSnGBOPxLM+J6230/h7v\nWJ8myE1jxDwIPQCDi1A16yQfFbtyR1GheJXVlrlX4YV5We22SIfUK/wmMr+s\nbZcMOcVFqL0Hvo3evBJGoP8v5q9tXXBOVFF6e49QDZbINgYIBTZ/uotFQz9X\no800Lf4XGK0AGnlEapjw+xszhQjpu+njCL4w83Qk2aRAmOvsCFWQz50yL5uG\nV03ARQM6dSETHFfTd9LJ0PspGkmupu+D878lnZvbMjt9fS3VOuR0A1S+dbSH\nve6m\r\n=UYbE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD/8l6/f1wAcAnuHJbNn5Aqq9hrfMAWXFEhO1Vd/6a9ZAIhAJGLShHJf9RUDW3z6N8OXFhS78/PC9mh0Yk3bWf7sv2i"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.29_1595857975721_0.31742294912561"},"_hasShrinkwrap":false},"1.0.0-alpha.30":{"name":"@joist/component","version":"1.0.0-alpha.30","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-alpha.30"},"gitHead":"95279610dab36395ab5dd9099a2f82f59ede3582","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-alpha.30","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-zQc6ZpZyzIkHaLRxtXicKZW6zEut1dAtL08NWJLU33vc0tob8cPcwY5rhdDOguiwVtRddj3Yb239uDBpC9CNUA==","shasum":"1b3b367ab9b3fa670269eb239e74076bd1693789","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-alpha.30.tgz","fileCount":41,"unpackedSize":32511,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHyqqCRA9TVsSAnZWagAA4toP+QCSHP1qUYrgpqbKk9sh\nWCfAFV8mEw6llBF+qopcPR0Ues2vQOiHS7PT+pXO2XzH3dhHWiihLfnduO1p\nJLwwZqVn6UDZcP0myczg3/l288CGuN1gZ7HTny0VjlXaT6LBiVCyTVKP4Osn\nMzInsJWNHdFju7ZB90QugfAONglRvc0Vi97MiRnR0+HdeY9UddMhAxeiW5/v\nmCScWwXeUcPToVESmEBjJzpir5Z1A9dlv/SQwokp+yuxMjioyH/qUg/GkURP\neTfOyCBZdQ2lD4Ja3b5O2CnZklpixx7ZtrGJaX5ouL7huCYE9GYXD1Wdh+UN\nHVuZeUXqYhQEVLi++rl3CQq2zo+yaKzrxIrAb5SpHFFMZKIs3bcTMULrogSr\nqoE+zna+UOVWx18rF6Eutb92uPcD90k+4FuZ4paDr5cI/0WNF3twCP0S21u0\n0gdpGwTchRcvolsMko7/t+aJnKRv6kNZR9IM2pNqD7Aw3uFqNYEDKLs0nbz5\nWPuSrHAtWW3eMOE74FRcjwZt3bXoG+4ThHMTrt5fP6JUQsQZI9RElst6nhmj\nmZJ9uvzKW6U2URyqIBlbwDeRVQujxmgcgdNyNLBsl0M2y3Qu5sGisI7dd+7Q\nW5w4m+kFgMcSsyoxOYx1aho3zk+e797E78ZDEgRlzS5DHNaN0H41EE3bBIRZ\nYReq\r\n=/MCD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCo5RBseVFQWe9Kvsizi6h0MH7ml4PCgt9QDvOw8NZ9pQIgP7qNXM1Ds5tqx5app71t/DETPYeW3++8UuIAORdkZFE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-alpha.30_1595878058151_0.957098217727129"},"_hasShrinkwrap":false},"1.0.0-beta.0":{"name":"@joist/component","version":"1.0.0-beta.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-beta.0"},"gitHead":"51af4566cc58e7542c246c816a5f0fb2b1bf6fad","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-beta.0","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-HAmwLCyyN1GNLTX1VibsI8rDnNQ+2TUhxdD+HOMJNZJw8g3Pjs8sxAT3xYioZGegDm95kqL52wXzqsM/SkUaCg==","shasum":"33e1972d016dfe0460a8c844c7376bccc88f98ab","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-beta.0.tgz","fileCount":41,"unpackedSize":32507,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHyrWCRA9TVsSAnZWagAAZDcP/3XBS6ts1zdPuAY0Xst7\nJZPxJz399g4FH+ptTmev1C5GoQruuy+Y8LFnGkIhVN5uyjagYfBEE+Q4isua\nxkXBax1EcAOv4lWd6psV75gjzvLM5SV5kM1NcAf+V7Hpoclvz94gjyOdL1ha\nZUMXBuv0IDVoMth1oyJT/AFFQlYZp428NCTuqxDTL5/jKOMdmrldahPHfunB\niSIXfVTMO2MSLI/H+YzFSe0F2Nr9Qu0iZmxFiCSrIbQhXZ9XcdOFpldedn7d\noPKbzlcOYRzQcQ90OpRPVLLIsfs0FyXJtvzhMVbj8m7ma95p3qkthKI9godz\nohI++5HmEnVohmj/8HrGEfnzyxlfg/MMRWmHH9RkT5IEKiKkUikYQA432bmX\nuTBTwg0FV6w5m6ebgBOJjkqJDsjWIFe2FUYm8oSSQskuTNHaUYDxfwAsf/v5\nTqRYmUDTBz1Cbqe4Wt8i82lCf5QxlyfyGQtbqMe7jslz7kID2Ohk1LapFSlf\nzkxl1nvkImHapjFaUFzoM3IGupHxYQLEmM29rt51qqk8suyJRpEfbZ7ckpwi\nqjvYsmdZFH88/HeOKDuz1ZrcfMisADlo/MEFuGJG2bnKkyXvdDEPzrOelKbC\njRtO5ll1FFjHq0cmXcWbk0PSOkU0FZQks9JXubhxxIpovPz2/diAFWYLZmBt\nIxdC\r\n=3E0s\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDqON/+RNcjBZTgKWC79aPIwtc/1aPwr1UQDdJD1F0iPwIgFXzLwG+1wiloNS7S565J3SRMwxG/ayRTWp8oFbffwik="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-beta.0_1595878101714_0.057978658912955394"},"_hasShrinkwrap":false},"1.0.0-beta.1":{"name":"@joist/component","version":"1.0.0-beta.1","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-beta.1"},"gitHead":"b24e84e2740ce394f17a76d6cdd7ac552a5615a8","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-beta.1","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-A++3WFc2/M+ii3YmrPD5F6+2oeSJwPw5hDDuHbuf1synJ//vQiUvnBVbIQHCKYLmPd2+dThoV5r5u01tZE2w1Q==","shasum":"51a611bb1bbd43d9a94f00c3f319a7eeb1b87f23","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-beta.1.tgz","fileCount":41,"unpackedSize":32619,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfHy2ICRA9TVsSAnZWagAAdm4P/25WlJ3qYwKhWihzDTNd\nVYA4dxw9oIYaum0QD0ZgtTOJP7T8O5fELvYdv1ldzF03R/matpUFg8Xfbb08\ns0GrA25DY5J7vRMPpGgdNR170dZVPStVbp2Bvyfez1FNYwed3gd2D+7XyhUZ\nEzZ8lzzIpKc+jzs2z1eudfCby8TWYRhspqz+h4hCBpZTIRqdjowkxKKzNq/k\ndttYquCidNcvJw0MPiZMMDgubaz4MMEV3nunipyDvQYM+SGUstKbATOeghXp\nJkv2y58AL4CMDxZWUGznk/mjPv+pyIWJRrhJTGCiO3K4/YfmhO5e2CwYVWql\n5j+gluJRT/zVJKW8fTXrLkMLZvYIGJqyO9b/uj67Nv+j01qAresXSAOykd1Z\nw1zStYGSIYfgVs/KxLDzUn3AKQRMkBwXHoc9UizaMUDAPZftEwLUGsrA3eyR\nPNpTzMJkECEXm7G7WayvK8uUqxzUYmG5DgfeaFL7Ob5FwQGkgvC9NwTDmnXL\n8IcCowMQEcm6HT92dQs4j0r73AaRNlEp9FgwKAm5PlEATGhYe9EFwgA1Qsr0\nlc917YvvZVvLr1HpGD4EanDnAOzTOPude7/WkxEIghllgmN4Js9JDinibthZ\n4Kyc9SA0UmDMdGRYGG5CUlygdwCJGKsRykIQDqt0JIw71W3yTAYL/KXocBAm\nwlOC\r\n=T9n+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCnspR+5Iz6A7QfvFyPHe/eckZZGTayFjSNCQ3DXEMuqAIhALUoE5OewBCp7gtpp4xdYE9BQyL7/XDxlpajVrDzc14q"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-beta.1_1595878792448_0.5880789798063397"},"_hasShrinkwrap":false},"1.0.0-beta.2":{"name":"@joist/component","version":"1.0.0-beta.2","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-beta.2"},"gitHead":"59751206467601a6d08a2ecda126ebb7edcdd0e2","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-beta.2","_nodeVersion":"14.6.0","_npmVersion":"lerna/3.22.1/node@v14.6.0+x64 (linux)","dist":{"integrity":"sha512-GmaPy3f7v13/vURqp2b3T2fjx9KE6d/tdJL0bbKMKn7+Ta02LjhbYh9r+S0q0owhCWxDbzuiSCgGQhpI1ClEsw==","shasum":"5f0e808603351e80ee8d086f13e98271c035e7e2","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-beta.2.tgz","fileCount":41,"unpackedSize":33711,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfH4r0CRA9TVsSAnZWagAAm6UP/jvuyHxpG+2Jir4pUhQR\nep6nWG0fFlMipGIt1NrhjE17rzhIqAzTKfKF4zq26aTZ0elrkd1t364G2P+w\nNZlWVRl8ajjFFx/0qW9loCHjd31uWpaW50KAhGKIRIwdKPZHMZosZ3e667Jg\naI6kQ6jelpjjor7yf/uHJZWT0rv3HqwyqVZb4d92GT36sXofDws2wEWl9BuK\nXgjSGUEXxl8JNzWpTQmpahqpRomVD8MsZ83jnyrkCsY936m/d43qo8gjh7+0\ntWtJgv3rqdoenNgzLC99IZNHg+t196HowoDF7+PZ/zNl2uyxO64/67so8ucW\nhe7SLqPjsK5etvYD4TjuHHlb3bb1ca6pQ9J0Dl66yinESUSh4GOnsgKQWg/y\n9Ljcxstcc66UYPOqRw0zkGvUl2EUsaK+IjjiS2kByJ8j7OreXjk+MK3bCll8\n3aptaX6bSUziPXgICereY601e0lSAdbS7U0Y8g9r2Mhd5P06hUwb6Y0Iyd/f\nGipfpRKFSqQuHnDtyCIDK11MK7h4I+BbQOKtReJhxceGNG9jK+i4lAc5F5Km\nqK2kuCP+3LZrRxAcRHdE+RPnrm8jztfJuHpOpGuBFZFJ5h6ebXIXBB63tKTA\nUvLUXXeQi6wMxi3h1vGtrgP7DE6pGIS5w3m39G+9yWcdcsYzF9jSJGqZfnPp\nJCnT\r\n=Ews1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDwQUY9a6J7ZgLtGhYYlW26gqE+SpZpXJsVlSXGu7musAiAIEzYDyPwtZ0+NC8FQFZjUwzDg/hlqR6/iTEw2cy3amw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-beta.2_1595902707734_0.6581051345861613"},"_hasShrinkwrap":false},"1.0.0-beta.3":{"name":"@joist/component","version":"1.0.0-beta.3","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0-beta.3"},"gitHead":"891067afd95203019fc32b486e5f3e889e1f8f72","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0-beta.3","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-ID6qmIr1/MSL1YkmWUE3DbnonRLBD3miiX7kOFec6DxHGk+AIygYyiZPK8P40yynqE8wjb3MCS7odmFXraxtbQ==","shasum":"ed8a58e10b627e7a35fb0eb2357c76042501b9fb","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0-beta.3.tgz","fileCount":38,"unpackedSize":31626,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfIEDBCRA9TVsSAnZWagAATKwQAIacHxp5uG+MZQRZYrUD\n5IkRooEiPOGtbTXIAIXK9jfWbMsY/j00LjNmLRBV+2jaRI4o/xv4anu/JMzQ\nanifzQJp1jRRWR3G40CX63x37ALKwfhPJKzHneiqNxdEzLJ6gu3ySN6K+457\n8ct0Z5qFCkzgd3yyZQOhh6Brmt8ZmVcNrk+9tSxwfHgMevOtFLWrX0OVnNp+\nJQzBx/xaA6JkooFZpo4MclsyUakyTX9biYktIPm5+3XKguwBk/zWkHIJuWYz\nfTAJNgDrwKaWDUGW+/PwSdCVC0dhRATAgBWNGuJu1k9A4iVFn+YpxNgXBHjI\nNouWCBSRLyl6k2ty0w1NQzXwStFCwBMrri296RcFKHgcKC8uCUzoRTT9Ubrr\nO42Acavc9LVAFPqzCa0PuvXrowRbEGHUqKeAvk2kIqQhpRBKn3CxCWxToM1P\nNTyvYX/34EzOSB9xJq+qWIVmkd3m4r/ht99TYhUkHRo5ytoRWvITwiAApR8p\n/xrsJiNijsvyLaEv95ERBeolfBqHOU3K9jC3a2a/h+QypMaHMRu/36Fci7Oj\nW4qqSatrYrOABv9BtIijfrmcF2RcWQfKlb7v5DytB8IYy1EIkqazlbeJO9lo\n7Y3ROXSQO/1TuOIuZLKSpbdJpSGGRuVslBhhH8VEDgeZQM93rqZV1GxggsOO\n7bvl\r\n=Efq5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD5beN2wAYpDtX4Ohf0uE197ji7D40QUyO3AfPPkDgTFwIgHJ2UxehJjAdFhl2+ioLJKseircr1HHnb9lSqDE7KzSM="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0-beta.3_1595949249334_0.9249706476281752"},"_hasShrinkwrap":false},"1.0.0":{"name":"@joist/component","version":"1.0.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"Framework around Lit-Html","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.0"},"gitHead":"be3d1eb530685e9fd62c89ea15255066a71956e2","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.0","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-4TL1jIDkDry09qSBhIBkaaI9CP1jUyUwIW8mRsBQwjaUDk4I41WlrcBLGz3EWfNr77fnI6eB62EWmVTxoDXThg==","shasum":"42ae744ff36fa39d8c380a0bf4d944ea0a830cfc","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.0.tgz","fileCount":38,"unpackedSize":31612,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfIE3ACRA9TVsSAnZWagAAPegP/i/ZJaC0Wcis7XN9R0ik\nXHjbL85LXXrEHQKoWw4+q1EVwpxR77F1hGV68Ojj0yS7j/dnGiq//xTgq7/+\nFFB0tIBu/7OFo+6Iu9gL1fMl7CMQra+pxgfUiH0HEIcvQ+o35NkDj3uwZeN2\nFlF80vK+rMrSehQUk9qazkyOuyvdwnVlvLeCXr0deZYma7GJjPmrqiko1HaU\nEWKT20KgATopiuuTvdlUHrEF2s96K9YGs8mBGUAOHEgxYtEWQH/VuuszBwoX\n8GVa6BvdKhSddoTuPRYNlMUNzaQyGCrkHypl5w2PFzGXYjPE5+qt1/YMFAG3\nbfhuYw+qMY5qms6/hrkhNPxoGWWfvVsj6vRyJYFRiks/YdlWWf+zwapJ+c1I\nv54sNJdu8kgkxXNBUZ4xZxVuCuIiBamUe8lhrNg/8TVlvIkU9D5uTtuKJ66i\nvma27LVt4D8kPQanrItma2tpAq5XLyldhSHEVAaknHs5yg6A89CCF78BqbcP\nzLT46LebxpyF1tU5s5TUVZ+5tcUVONJq0kz0IZ1/Oy2wmQFVV0hLywoSpl3s\nidrKBKl2+2ex1VBctrNl5t9NLEu322oNpbaOli7XsxDbgbMqUYEqfs7Q7/wU\nix6DZDrF/Rv8qL0uqthN1s5VWWG+YRhTHVKat6WY1UR+Q/XDH/rsnny2B01N\n7xRL\r\n=q5Ti\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCLhkAq/sSURVgr7VhdF4CvXY04MDfqos/MvR4Ya6jASAIhALSE0k0ojco00pDOk+72Lg2otnXoqEuHQxU4IX03e5i7"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.0_1595952575715_0.15364137758731555"},"_hasShrinkwrap":false},"1.0.1":{"name":"@joist/component","version":"1.0.1","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.1"},"gitHead":"1867e0fa256bffcac956d644986ebbc045f332f6","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.1","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-H7gqN3rbc7UztRFlu3bG76skUG8zGw49X54F2kGILUl4zReaEm58dNs4W3ox5cEjAif75UivdMK+29xGlafAQA==","shasum":"38f995322bba86f211bd6e5738349bfabb932bea","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.1.tgz","fileCount":38,"unpackedSize":31875,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfJIysCRA9TVsSAnZWagAAgwgP/1LpF5Xc/YSis+c6mGW7\ndQ+lOnpHfb9XhR8L5IxnMShKRJYGtfK5FsslNEdj9ePMGBRlL66vYZxhLA2d\nTxQsVg9kXFhr0MlbzdQUMUhoz8aoAW6Z2hOF56oXuiZALy8uH+c2szRrRvxL\nClNWe4zKyfaAL32p3Kcnzem7B6X+zAYMQGwjyCC7cZOpYHcVXlWUieNZ52F9\nQZrufT8Yvy1QPyrHSBE5aZYAAdlxK8sZwRBgG+q3weJGfAdPcA5jtD3p9T4E\nGAuHRnKN8auUS/LfX665EhJ39Lo2XKW5XIwi/nk5oynZTTyCPXzaExWJEqKu\na4y3YGlnTfy+iiuPW7LE/tTiHZ7JdXmDwbdNZo/55DiC0R8D6hCdPZL+oCF0\n+ecRIe7xwQiiAkaxGawZraqzwP1RN4S/WxNPtu1/d8/lfe+hOw1yJCeL1Ocq\n6Abv44S4trR2mefq8MzXLSZ+tB39xeOWFxE2h01OJ9ufn/WngFYaRC0Wz1lz\nw/RchIPONUXjgY1foP4+cORtFZkfPM+OywNg2UbRbKVA0WEmO9sgFefSEigZ\n0CzRfjNeAFbnn7I4PxQyH+2ZbNG56mx1BZf19Q2Dwm+jsSSHeavH+XadlRvT\nRiPEoVslp1UkBaqKUsE3B/W5jUKDj2kFvLAxZs5YZerQyBxcV/lmndi3a+Jq\n6XUw\r\n=Q8/U\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGVZ9/VLx/yQlq0i/EaSkvDAmJIbvt1usuOTqGXhjnAyAiEA8BYTICBHo83VbVgvFGV0Po8EFXi5jDqkVVKPBisEYjg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.1_1596230828205_0.17016844419482235"},"_hasShrinkwrap":false},"1.0.2":{"name":"@joist/component","version":"1.0.2","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.2"},"gitHead":"3819537fd18307372e2b8cc5ebb12de985301779","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.2","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-C8/1fzI+EHlEjwhb9fBTxMrvfHH007mCR2F/kMwu7hOcy+8pB2757/3nL/I6x85V01Kh+1XUHOII9nV+vV+DKA==","shasum":"466593951d82f15ebb1f4d6745af25574aa70303","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.2.tgz","fileCount":38,"unpackedSize":31875,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfJLk8CRA9TVsSAnZWagAAngwP/0FLXsEuuouBzlZ7kfuN\nyqNbxXmslS9bElErdIkzGegL4zQdeicRvMa4r0Mrmew4ONapxmClTput4PGa\nDjgyEukdb2m0nr6Q50jGXXtumyIKsPzD+AQIC1rcZJk2ugphtrkKFKpz4uJ5\n8opyAAGNbN3q7lqV5BL1LpaWLSU3TSEFWQNr9NGgAeXAGYFAFeJvcPfAArXm\nzJpBY9AehlGMwFrOLjhAJyKNvViFQPbpj/zxYR+EChSpNCeubEELpFA1r+/Z\nNgMWj0HZbiod/SlwvBlGmC5ZDPzgzAz3gCcket77wWxPd91brN3zQYgL8H1R\nHnlK93v5tx0C3K9sXsbt2fdPqDE1CXoIXm3EhxaVCc3gYqsNJCv7QZHaVbLF\npyB2s6y7RPS8GMb4tKT3Z3oFTFmnevghaK37dQLgSiBTedQUjShC5ljf7bFQ\nYCeQt+BhR+PBANt1TJY/0Qe1E2YNhbV1aro0FdbvSZDodrLY8oAQekFzP0Ct\naZsPf1D6czchxkf1s71QRE/vvqjCESMFOyUcPykbziQRwmEz3hNydZuZKy4J\nfmqX1tx+sGjwqfJ1S078fs/plDsucRwBbpAzmWrgzhvaQ8b7XwpvX94NQNrm\nbrJ0k4iJNIpITIZ5+2Tx46XasfVFPksCTlOsseStoTrXbv8ei0AO5Y7qEwcl\nHVAX\r\n=i+YW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHKEq3geAIFLEfi4hUc8dIeJhqm2OdpFeTDN7/3isw1AAiEAlzu9zEhetyta3sKIxHQB701xzzsYHWwEAoZHSx9n2Vg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.2_1596242236086_0.331790647282316"},"_hasShrinkwrap":false},"1.0.3":{"name":"@joist/component","version":"1.0.3","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.3"},"gitHead":"c4073cc044948450b42dab233473893a777f5643","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.3","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-nYKt9Yo3vjW6r3sVbY0vW6DeLuYkzn3jVtXWEu+kXq85rZgfv1YPb/W5p61WOr0qWmP51W6/y+Juyo7rkSzVGg==","shasum":"ccd56a2689a62b8e0fdc79c2421b105a0d4a3de5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.3.tgz","fileCount":38,"unpackedSize":31875,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfJMIpCRA9TVsSAnZWagAAzCcP/AhnAwc8CmZ+Hl50KtvF\nFZmcZzMrJW0bLhg2Xgb54iigGFU21hXWRjNf9jK+K9DGGyzpmrBHjVZIPEBr\nOLiDR0YQXJ6b8BNNNEUeppmJMwSsUa3fVaoIiX4Q+NLuhVdp2Xg3MpFrEh6F\nlmw8qdNr/Yqrg/CRFuM8m+DoCGmEHwHa+miJWheseZkarn7sxZDPglG+f1RQ\n7Hs5X583SjLP3qu6DudZQMju2VH2I/n9kSLDT+tI4gmPh99bluBfry/nG9Hs\nHjhA6TT+3l9PgLu/gSM4PF2eH2qMMWTdifuxCYmo09Rmxgv57BtZoTmxBlPL\nO7JgNVJlPYEIqAkEx0Rf+CTK7qZvRfaXb8cPyuU+bdIyVlAK6GqqQjQ6n6pY\n4Te1ESxD/BOQL9jd+RspdxKWKQnhWPQCnPYtBqImfUJ+hFFGGATF5kSCd1Bs\nWLODW5aaV8geKhOSkeank/qQgwikbKGcfjN+GyipENUbYSUrnCGjZLZvwyLf\nQypiS4EVg3RiayptC9/pbOK2B0IE5iAaZi3iz4MvKYJHVweqRPAPsbWeg/sZ\nRQBKGrrQzm2rgaHN7S5+Ly2gnJKsE4It3YdEvHtfPC4BhoaZFykDMqlULqWi\nXPT8lJsWX1M4YLBBYSBQWWlXOiYMwbADig5OawFx4dIfMNp3Ek7ZgD0f4yIt\n+ESR\r\n=SUf/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDZ88sbGkLczecR01ui+LNcSRVMA3yYwhNphh0CuLJqKAiEAo0JydPTdTJfMz/TT8SB3j6iEclkSfw5u6eqIvkE6PBw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.3_1596244520470_0.23273991199979793"},"_hasShrinkwrap":false},"1.0.4":{"name":"@joist/component","version":"1.0.4","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.4"},"gitHead":"90f55c4f0677b6626b0490f80494b7d477cfcdf9","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.4","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-RMrWp6Vpmtt1P+VMe54SvnmtAUlb85kb/EjofN3TYFqzyH08UNqWbstNUQE6qPyghhpauJmVDOMiKUTG5tVEKQ==","shasum":"5702807099e15500b5b02a75ba10d3a7d32172c6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.4.tgz","fileCount":37,"unpackedSize":30817,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfJ3O8CRA9TVsSAnZWagAADfYP/j12Wl3e/+hBwaaaRtSN\nZKo+XCJ7D5r8S9ZENHZsRqLeNcyQWOnMJAbp3f9cRt1z7C1BHFEo1iZeF4f+\nQp0v2q/TxCJ08EuDXXX/gu/Ucby/XZh0pe+GEc24tWxNEuhVZs+EkmqpwUeR\nVcrDqSbzIcI+GZL4nzb49szNKR9xUORDM6qmXAZFkfju7gxIbPrGyW2JI/tM\nUVMTNShIWjCdny5CfLd+9H14TfC9IbutPG3wvEvaq+qGFwQ9uuDNXdnMAOTO\nrchwNkcUkrd/3oinkqWPL8I9lho54RpQcu7X5GflngJXApolItni8aSiYemq\no0Mu1+fVoZTAi52FsjM9MRo6NtACXmes0xf5rFUSiSSqrNyWvVdc3OmgLbD/\nh3dPGpLT/RQWGMfaXQ7hxX3ixgPiYelYXlRlOY3Cb5kMFLECswd1jjLLTmv6\nwdhZmIOIJX64fOkFCZ+//zH+0AuuYbRvp5f6lCZ8JPb+Cl6Xo80XmkaMQYti\nN6ODIlwRxLLYhHO9xy5hOgza+i5+/CFbyu9Lr/D183EafL3c9LP/iJ0ZO8ZO\nFeXW3Vp1ou5LhYg9sXVAnatpRq2Mxdzd8CCE5KkJQgNJNs8t0IBxjWS6PPKz\nJXBdD/UtKDZAphOn7OXWD1KY6Lgf+ulCY65SSCZ2PBWXUrJGU9WagMawffvu\nKe2Z\r\n=gH6J\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQChkVWjZ3Dk+j2B0js9qULxC2lsQIsgWx/qffswXaE0hwIgXjrLCj8sEZ/XaG2GQw3sw12tYpLqjm3/fPOGNlsuITM="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.4_1596421051818_0.11385042653694244"},"_hasShrinkwrap":false},"1.0.5":{"name":"@joist/component","version":"1.0.5","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.5"},"gitHead":"335c38fdb58a9d82bfac8f0c434f895aeeef4466","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.5","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-ztFFujtC7P6SwkCMUqe+/F/fAcXQ58RYBu/txBMStdJzP6mzYRBXadgtAE2Fzx83OIw+oTeRzKmnM3KlAjkbZA==","shasum":"81980cc8847382a1c0edef0a706adf1b3074f47f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.5.tgz","fileCount":37,"unpackedSize":30986,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfJ3sdCRA9TVsSAnZWagAA9McP/R1wJCTo99HbGLnAA3dX\nw5Mr3zhJsrY6x9of6FysUrP4id4tZswuLqkoaN+7AvFM+yv9e6JzKKFjAzit\nZVRfH5x2GRTum8RB09byUhRH7uZA1t4ikDCBCeCWhdv5ARoaUnRp/I+28Gqn\nW4f3+UYwsSZGUoBqWk816l+QIu9llLCJzie3xCJHgFcZ41MKaa6yq3VOk2+9\nLq235443KO6cVij4oIYnCvNBREeGM6tR4V4LVx+0m97SFbSzxO8wcnipr2Mm\nlNEU2YrThNItXJnZR9trTMuxEUZvoQKUfc6cEce9s3xpvdXw2i94513E+sbe\nfhFmT8fYqmOM+3+7AdRSh9TgU3W6qV/jQkydo2iR28MHx7pX1ZfGinpHXy6z\nkuTJ8lvDna7gOhmlJrmKwVm1lVlB66ZumDleWTd5M2QnhY/huP4t+sv3cMVu\nxlIWV7E/BLLF4Kq+Eo6zUpqRehCjBL7wyGfRt8gL9N9Qb9OXmlykdKZmurCD\nId6j1WCQ/65PCGMXPWenY6/IOHXDaN+DJbaH1DfsMF07EGnv+pUodtkWT+0x\nen8AEa4dwkRJzEuX9NeQ5DnEVdHRPwJ0FoqNNg6IQ4LM+z0o7WjybvrZCre0\nAkg1KWcLc2NRqJp3v7DshfyLOVIasjn3x3Zz3IGQq64oWEfp+2nR6z14eTjN\nxHdM\r\n=Xqtz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCe3Vf6EIAMt8yDHYblmjQIcYQv0TqPTH9fi5bDsJQazgIhAKV7Lq5F09Q8Pqx/Te8ks6qSKyyYxye8Ct2dUy3DYoO3"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.5_1596422940702_0.3521362084588504"},"_hasShrinkwrap":false},"1.0.6":{"name":"@joist/component","version":"1.0.6","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.6"},"gitHead":"d6a9d3d6206c718ca0b107bbf7535ec23cdaa386","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.6","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-Cd+42LcAUQII07mznrIPAvtb5TPfR3f7GyfXrCPl6QFj14YcyYJu+VkIya7+FFH89ZNnPM1jUPXwoZZ/WqBTgw==","shasum":"5ec460c6b950e6bdd58a3097a59fe6358ddf8b36","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.6.tgz","fileCount":37,"unpackedSize":31342,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfKF4UCRA9TVsSAnZWagAAIyUP/2UEhPHqErdSmlILXWsW\nOkds1lWMdqfqkIqq/QmeNIoR4vqqdqhD4R41xNZ3f+dxVcJ+aBvGfGhpf9mF\nuDxf7XLoJWmFuF3nKi9kWECmlcGZuH86SL2Gy5bxCSVywY7mjMHaTz6pN8Gz\neQN2YVNvuudjxwA1qGFhSKAbEOR2kGPz4r2tUIxiEMltFW4WE2XaVdt/NU4s\nstHJvUg+6wFzdp99p1OipSdT0rVtfHtRSYPpSG+nK5SqQMewUUcXPASnx6Hb\n3hsGfAogN/rtxNfjQvWaIxhDRzRa8a5jlWMj2WVhmtOyyo7IOFOGcdfoMoo2\n/Yo+OSNSwVpn+EQTLvNx+9+TUUEjZwmZqSfGNk/+UELhbKgdQ+AgMk6tMR/v\ndTy/4bUMonA7n6zt70YSFF4r3RJWZQRDM+2ARWWO/wKGbNmlesWIkzzAq3es\nO5hEJUipg5jRHRm1beEhV1l4TJkdBOAWJzVOgG6whmTjnhpwxEj73/+QtIxo\n7BGjVuoo+iZZTKdt+BsqZzZHUPV0nACR5xoXg/j4SOixF/wTPCif7W2ZRwZ1\nD/ydkan88296XfbcVY6V/C0S+jQSpe64zM7okFJ77tgOefAv02XR01gML4Nf\n2m8jmcbPccZp20/UlFfOzzCi3o5I7QcZTyzJUrs+FUdRmZ9Q45VZVmFnsMfj\ndyL2\r\n=FMX1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCy86eUHyYlkrrQlWgVRPFXG5zhIhIsO+pl7rWv1xTyywIgH4OEgCmVKKmSJrV9UU7uz2fHpQv4RMDPFhedHHABNu8="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.6_1596481044344_0.8817395943295216"},"_hasShrinkwrap":false},"1.0.7":{"name":"@joist/component","version":"1.0.7","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.7"},"gitHead":"83caa1b6379902b8384a08b4168c9d34af426e2d","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.7","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-EMhOE6Z4GT0pUOanc2m4dizFBJCFXcq5f46ixz2ZuStuy9Ct8v/KAMQOav8Rh/8nfvIRkSCDg+Em8tBAci/NgQ==","shasum":"3d1d69923d3b03fd3c3ccad64665cb9a3091da0a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.7.tgz","fileCount":37,"unpackedSize":31342,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfKus4CRA9TVsSAnZWagAAT1gP/07070lHOBIrDmytdsJw\nv7T9i4hMUnte9keKXVska85+QqOVxw3T+YTx2GvSHZiFrnxXG7dhX/ADdkrx\na65rLqQE0FeCS9icSYkkTuks9zpWEvmSxhYeSgJQYR/hykHqSW31ImFtGimL\nQaBcTa1jPRwS9sm6UN8atNqkdmOLVzcUY+DcCxZXXuKYDLQCJjwWS6XQQO7Z\nxPptYPqFXVcPnObW4IHOeFKiYkG8jFtiXFyUrU1ekjSEb1UChxQK+/l9GzzQ\nCo8Z2k3kOHrTXy+2kD8TiRIIP2lFNrLiQNDfp6+kVyYnWlg/Upp/uZLt77An\nYORtcoo2T656iNo9wbAjDUb9cGn6yHanbpmJriHg0Cc1ATCO+cYkomIUeRl4\noqbFbUZxPIANSa2GUObp+gsA8Db4jjpfkkK5KRz5wB+hZc5HGLv6J5Pr25rE\n8c+RKPb402OxiBDZZuxKOWCN7nKeXbiHm7RM9Z85ihP7nzHpFsS7rJSL+LEx\n56XSzLOwH9w6nCfkJibsmJppQ33IDGi/Gje98cXipYXaKAAFd1awkcJG+hN0\n3jvb7eFKSbDc1HFwJ3xo5j6l3oH4X/S7pIh7bN4m8TESXDFhv2/Cyz0bqtix\nD0pdWARNunyi5ALCsS1boEI4lHjQ4Bl55PZNUJHDYEn0AGv//F71bVa0R0qw\njsbb\r\n=UHkT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBou/F5As5EccZJlycUtfuUMkuqDmWsfKvbubF6cU0zhAiBlAWBW4bfA3/xKRMuL9PyPmMKasA9HRTi7w3xrxtydmA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.7_1596648248354_0.7019284224939106"},"_hasShrinkwrap":false},"1.0.8":{"name":"@joist/component","version":"1.0.8","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.8"},"gitHead":"267f797c53c9277ba60f9b4a8d2c5efd256659b5","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.8","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-qd21oKGyvgtgzv4fdHbrcMsqFbOeNJKPPilomXWiT+5b74SDHXhPi2SuxMV2+CHR1/VV2/8RkDtZMPm1/Mfwww==","shasum":"0ff712fc73c3aa8c9b287b1814893d46941d20c0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.8.tgz","fileCount":37,"unpackedSize":31342,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfKv49CRA9TVsSAnZWagAAtJUP/RaXPjuKA8fKZVTwkX9L\nWS8JfnlE0DgWMJei8LC2lXJhDSSjUp0TssVI9ukGU6bo7IszJWfoZBGI9DS/\n3FBMmLdnNOqqcSuZW++WiQUPXy9II3z+Rgsp/K25zhybNg4KQ1EB/VYiAaBx\nMCDpTErhuOnuWXxIa6xL/AddGTFtTFDPFP9ZcurPXTSzKo5MJvhf1FuxoG08\neFAhQg8yYuYqD8ts8cM36suDDhsvhrnCm7yWc1lNVIFXOqjmaNGDdNdWr9zG\nqhcUkFertj20Vtc+Y6mozMcMtUgIUI0zrsnFORlI/7PBKRsmNHe5HxfgJTd/\nmlwxkseOgiF74sINJhBRsg9fyo1gliBONyTReVppgmyv7Jy0aZVRYOp10dv5\nxMWPdUGvl0JZzzvz86eZCYAZpATaAkXXU0ppLHn1XzW3pYaUMlAYemGerCvS\nxTWVWAFF7ean6rlAzdqjPPXNWwaPZHhOEQ9+F93hcHc8ZP3KK3E+vcnMva63\nWnaGY+kuimZAzSvbLf51hfaHk5+7GefrlF20bCQqNNTqRS+tSw2L/ml2WUWs\nmFy3LPClDKlCdZUWKf7prgtEYYGhMSDBobhrbBWKf5mym8HLd/DuLpIa1YnA\nSghelyAc4PrL90ZXJJOg9hWk95NsuQTVfmVjE0IE9zPl4E48sDGLxD0QJMTo\nryDs\r\n=K9+v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCpT3oy9FXe5U0H68c1d3Lk6TUpLlQyuaE9165N5Hr9bQIhAJgBDBjUOuYHrvJoaQWixQP/GOsrutADjRa+71bw0blj"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.8_1596653116901_0.8443636581748428"},"_hasShrinkwrap":false},"1.0.9":{"name":"@joist/component","version":"1.0.9","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.0.9"},"gitHead":"273497bf95b10ee9b4696dc8219f087b08c2b2f4","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.0.9","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-QP61HYJ+XoUSb15GklIsJsNAsZb3oYaRJ+soxLlkCLUpTAhnDAM03+8H9s+KBM3uu80nBetgMMatKXhUdEGMOA==","shasum":"38f77ed5fe222b8fc7118fe892d76129dbf852f1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.0.9.tgz","fileCount":37,"unpackedSize":31342,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfKyO5CRA9TVsSAnZWagAA0ecP/i72cgcLKq2V8oVeluX1\ndhqaEtNrNQC+vQqe9NxjTuSXh2hiQQ7a+qfGRAw8zwQM65nTK+D+IjLa0NTC\n2pa7pZFTr/+LyjxP8S9fAzm5PrK5/SP+qJ6Ndan6QKfKeRZwkvXgzSusAgjB\nmc5+KDTBlopBRV/B8zp7BqthyZFTM7b0TLbqClb+rmdWNNBdTRqzv5NMXiYa\nz7c3w0MuWhK9NYLV9bFV19ssncxtPrl4e1hXwC5lTW0rVv49YdUcXC6jRpUI\nB3ckAAil72YmcEAxiiG7LqkOVE+7PDPhvg5z/z4Yj4C7EOkfQ3KWzn4aKHKm\n9h0RXKOeKgRlblNqpOccMqB2FgW5+LARLHmMaMVRlljHzvqtQTEQVjnR/esO\nJ0DmCSNbRFQq06TxrSLLe+iUYUaKmLiUuKCftS5fRYa0HI2umq2y/1V4SrdU\n4hMGMK1S8EY5LoR+j0/SRq+ib3gVQE22c1buzzrIX6KBKGJYZmn4d4z36kgJ\nWjqyp/1xltdTZD6UI2O49AwrtBcFLMEMthojmy/uLWNVnEbvahKPoqZte3Ja\nHdJqgmBPNNLPq3ssXSyLAHmODTrtfHUfFLtF4sD3+nsnKTqO7U21MgZCplCl\nbFvekcLLoqxcnv3NhHZLsO3vQyMKGhIW+264fBYXyXfjhyU8laoYPXUBO2tP\nAtZg\r\n=nVIN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDc4AcDaUsxK94sniP5tuJ5UPNZnU8qqhwnAmvy8UGw3AiEA9EwQLSUonE+5/lRIuhG1LM+RgWwE0/eZUIPhQmP42ig="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.0.9_1596662712868_0.39724023471483294"},"_hasShrinkwrap":false},"1.1.0":{"name":"@joist/component","version":"1.1.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.0"},"gitHead":"b45b98e898f09628dfa87a8c0a54f49df75e1031","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.0","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-oY3WXD29AwnDCKqASmz4136ePUktc4mtlU5LresL690seL/qrmgqjE2ZP/mdQ4q5S/57Y9G4P2yUntSjDGdhpw==","shasum":"ac35cdf9a0ebdd70e2a03f0836ced1a74bdcd8b8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.0.tgz","fileCount":37,"unpackedSize":31594,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLC41CRA9TVsSAnZWagAAsv0P/1gD/duW1oAyQORUl4gm\nazhyM8g30x1DYc6Rt1GSy8A9v+OVD1mfUDXd+zV63m+2A25OWLachMBTuu2b\nKsQbxsqfPvqX2YBj106MlDHYEr2tro1Ow8IFud6ZkXOcel/A1de+otpsrqvn\nT/hIl32UNu0AqbL56FHnySIu2yXDFSE/zS8AfDtU547k8KQl9EkhFwBxgl7T\nSKzE/fvSdMd047I+PvZJ8N/BJSXPIJiKzgOv9TKsqz5D5yUFSNI+HOd2yMYP\nVrzLhknsoMJcMhzN26k6BlTxMCKBXhs1pmmJ29fZCbVV/T0/q+yUeLD8P9ob\ngnO9ZxBAu2XCEPK+DRuevybPJUdT7J6tNq1KtMTJU4wMphw1nbIHGQhJX3Py\n/S3EhM40hJGp+6HPoAm07cKOIRc2Q1r4qynD2u++QwWK0qfIe3uoMfa6FA4I\nENMHFqlOqU75WCoATEgUMsyM0KeRoLJmkdFBY2/47pLSZZl37zU5Kvb6rVr9\n2ZyH/EZ99+glCdKfbgNCzf3/lmshjrvYiS9rqdMzIReudu3zZW3gN+5w56e8\nC1CBokk32i2hgg2F17tgvTphepuoWc0dMBQ02WCxZ6Pypdp4Vz+Xjrq93IlH\ng5Hl96j0cSjU5aIpj3sGIfBNEdr7WBWl7eR+mmrU+3bo8tdYq6v4nRo+Sj1O\naSFr\r\n=UahB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDVfNW+NxMwxEHBELy8+qX2DdPHoFFh5/5bfSufXCYR+gIgR+VWmKJ39Y4yc7Zj1N8gJwQTqdPUdTWH46L/I0n/Xdk="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.0_1596730933143_0.9468924598971242"},"_hasShrinkwrap":false},"1.1.1":{"name":"@joist/component","version":"1.1.1","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.1"},"gitHead":"ffa023d8f5546efd86f541bf3462b37958bc5908","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.1","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-yryk1vf2R6ErOa3kLvMU7i3A+vFdWC+21Uf2Sh2TGGu/nU2GWUaLgtu2fNMq5AsVCiTKWRdnGzb8dyY07vYtLw==","shasum":"9a6ec42719a58072026f3ad677c50b977ec30ff1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.1.tgz","fileCount":49,"unpackedSize":57684,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLY5+CRA9TVsSAnZWagAAKREP/3VfPRtyNGaoiURqgQn2\nNM0mp6ZIht6sd1LFUul9m11wYgMYqYb5RojBh7U0WnqWSCa4/nA6C3U4MsQa\n9i2HV2htG09UvkS4ZwuZ1E8U3g8tKK1I0copZle7aJV4QeibBp2OiAtjlClF\nKbDyrX4PDmE1Ca7jgs7zZs8ZHeV9YRf33J+HnZ1Zt2rfsQQu81NPBAgVicTr\nnkOrjpEfCa9BXjz9F+BzP7V7NjsQsr+XHqJ6j0+yExJibv/kgbEjFtysvWww\nJ+dwsGZpK/qJmsG7D3g4j3kZe2V1vHvFFrIxcUNzWoOTpNd5LG9NvxOSh9iQ\na1o150RHTtUhD/OA0Ubm1XJXNTyfx9WryL+TGNsrItGT2mCV1brI5X2m4Ji8\n0nQcFR/dKowbcLGIPClWqUaFvx5z4jNsapVuHhUj//6PaD6+c3DtAZBwdvct\nsM1ySSbTlROBPAsFg56SaMTWXH7je/M/2cSYblKr3BgUK7hhbzjMr7HXeJHv\njgWd6Y5jKDsDwby4tsFLPokxemw4uKw22iUjVoMD/LGi23GXbJcEh2CqY12v\nJEoEL9brLzeWJ5coEU1DanoNQXqz8Dp9vi1aMtbzxZNwKEafkoz0xpBG5oFu\nyn7r5aoa7pLZH7UMUaQvSv3T+8dLO34oyBf1W3hSgToYgeDWYRk2jB/oDWpe\n1dcz\r\n=5xoj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFfJLWGkZVfUIxzAstADEIKgDejnwuyQwUzjrozGmqKVAiEAwFj45q7V5rrll7yTzKzGnkf/MzybC4ENMAW/9lftSqI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.1_1596821117723_0.35923328672296106"},"_hasShrinkwrap":false},"1.1.2":{"name":"@joist/component","version":"1.1.2","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.2"},"gitHead":"10810b52fb91d88b870d39bb065dd65d5920cefa","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.2","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-AZgEcqat+jMzdrgBYgD4tcOMTjunBx9oWrJPXZfT8YNpfmdqGMdV0zop4GqkrGkGq4StaPn/XVmH2Q5u1Px5GA==","shasum":"1d9a158e4db1032e8aca927ebd4cee9f29b19ec6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.2.tgz","fileCount":49,"unpackedSize":57684,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLY/2CRA9TVsSAnZWagAAGm4QAIGuG0Lck8sZrncvzUA8\nFHHQ7i/j7hAghLy2wGO8iiIp3sVXxpNjW6VN2fhzPuB9JYKoN/oAIR4BIZ61\nr2UbZYNhK2ootGEjaGfgrz8liSKZ/ZyZHFu4CfStgvNiPL2LfWKpP1ZV2GNM\n3N2GtnnnuEaalPZw8V+GLIIP+RPvlt3NjhDrY5mx8lkApL/IOWeJg2TcIyhc\nSIPmCFUR2BwzlWEHh+BTgj0rA+Fquo3hUEVVtgh6IK47YDfHKRNp/6usTKaW\nJ7LYvBBh7DDdLrsArU720URHdxzwxrBPvxHs4g2Xjg30A86wUDKXoD9ZoNQk\nqIwRSXLy0noPqZb7uLuxDYwKwuUW4BZlXPXpz6yoPIXlB6TrBfM04AVKGpmh\nofeOxUBarZ6p9nzhjFVGtJ9ZMbzeuCiqhQxUfpXnVRMKm2rxN2aainPfhDqD\nNu2OxchaLdj+SZU1x0qKrytmTe+MlWO/ywlHnvZmxB0L6FzKv9mkqjeoRtev\nCbJb8K0E/1070yUXPbBZuXqNDtaeebxyQshXRovfnVrCXRQjn5AI/U9rpOM0\n2f/7Dj3MqNJxcwdtjjgtebtkQKWr3/XR20qJJ5K94zBeKBZVh/9zFkVbJ7l1\nf1rwz/yu4xsp2HwZqMmd7Qc+JBY0Hl62tZpf8cvTIqQ+NYTcXJ3XgN83e5H7\nzmBU\r\n=5YWN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHjqXZvhgqvrW69xXlzL7GAUkUw7YHZwS23sWO+vhNYRAiEAtRv+WBTHLf1GfIdBgCjCaEKjbvy9caqViJSoT2Fpu6o="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.2_1596821493927_0.48865360449149864"},"_hasShrinkwrap":false},"1.1.3":{"name":"@joist/component","version":"1.1.3","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"karma start","build":"../../node_modules/.bin/tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.3"},"gitHead":"437778ac98c8de6565d6a2c678a1ddbc76632ddb","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.3","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-IwBzSjzXhF5Vg8S5Vbi0svczPbdn/KKmwZMrQ0pscwsV3YSyD8lTJpXN86D17mqmAUilUSm1VIAlvjXBKOk0/A==","shasum":"37724cd395c455c762ad749e55f2cc25fdb2249c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.3.tgz","fileCount":49,"unpackedSize":57684,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLZT+CRA9TVsSAnZWagAAB2EP/2BNqTo+VFAUlEJIgrVg\nSKxQXBg6k2gAL7KRUYm/oSLWHiud/ZHOCIRow5Qsi0GXB2zmt6b08xGBsglu\nM2IrfyXx4ec2VIgbBQS4jrI8dSguLFVc1NzQ1ZjsKRBwO/wjnPiP3+pWvNJQ\n20xP/tvHRCV3PqSI4UsGUzy1NDP4qQfpsGNKwfNaKXeCyT5CtbD3/m2ka33j\nwXgbWxCnXsezql6q0aMbN1PTb8RrZKp79xlNu7zL5p7HUjJF7yzG0Hl13bK+\nbhWn1mwsyx7mVo+5dOe6YVmyKz3VTcDgub6+7y3IzKk37KmBee1vYi4qqB2r\nzyE2As13sRav4X1uhcW8NMVegPnjSJjZRSbpyNHGZ0Xla/egEIMNeLul6cFp\nsLxMsQHUc0zayJxzaa2hrHtjvawXCPGtWUnfEriO2dFjwboc3hgdRPjnd59O\n5GS31VvhhDMwyKCPh1Cp+CcAS/f0jyxoDpg2WaCBvPVYjrpAaIAGM4JMR6H/\n2RJbTetqdy3IbRjs8+zHb3HXSzA1lTxwQJN9lAMXxRNlnfYr9jztpwdEQn6m\nde7i9NOdMAbhxIqlb0YD+tDINVgXbGoCP/Ieg1tVLZ7v53Ss0FtI24FmYMp3\n8BvmpYR0BBUkqp4ls5B0DcErmTAydfz9zP+1CyZuft9sQWTSOOIjqqocoA9O\nMra0\r\n=1iOm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDABq2J08yanYDeatfi73CSN5rDgzyGPoY6tlIArjIYLgIgb10pjBBz6A+kdAOMZ7GVGrDm7jOuADx6vp/twwp74i4="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.3_1596822782484_0.297982496539573"},"_hasShrinkwrap":false},"1.1.4-next.0":{"name":"@joist/component","version":"1.1.4-next.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.4-next.0+3a4ab7e"},"gitHead":"3a4ab7e991fbac281f9941a11cf11281c6b85375","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.4-next.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-0cU3gASj+INHv/y8yz+TkbygH5HbT+JfesPFdmwK5aUn9uiCVhLEHkkP+WYtL7sjXiQ2q0GaMwkCG71KKOKqAQ==","shasum":"b9c3d0424f443f8d167633ce90e8b9724cd1bfb1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.4-next.0.tgz","fileCount":31,"unpackedSize":29079,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLuyZCRA9TVsSAnZWagAAoGYP/R4xOQmnrmq3asPUgOhf\ndOYQ6u51qsYOwpUHNcDmArP67FHe2e6kMlTn+UdTfK6YIKj6i+UyrLDUzQr3\niC9frqlwr/iJfr4PYFVwpCS3EjXO4vpxBOcVYVcKTs3FGtQLMjPubc88wm5U\nwuwGilYxNQThGCe8P8f9jTZJljty/G34o2d618LPbAz21Vttc57WpYetd5ax\ntONOVVdM2SBxaNMbTtBgQWmsfubewG9nwgQ+lglAqBtZ8pLU3f3oECZaWWBH\nKl6lOzcE6NgWzV5ax41Vfa20KMrt6EXc7KGfo/vXrCPPFATzKa4b+S0Kpqwc\n/3/gQZMPervMhjCwx21/X6ZXWlD3dHOXU1kbYjxrvgsTuv5GWanntcdUi7p2\nRnIcqACRhSZW9PAH+GviVPLtzP8bED0053pDxdfWjqVOyubAOD1NsQF2iIrz\nvMRKYuZcK1tTwurnlIyFQM+L2/ZpblgJl5vNd69PvHlgWpUPlmapHLJIB8e0\nvxfnkTLEHTmqfYMuuYfQOHz82xhWiLW3He+yoTgSmx9vjbgUCmfF+o2IuSN1\njkPZre2kiIw3DlJWDiIK3Gi6BYjF0GZU5LlkYTeMQ8dT6gPzFA7M7LNxJvPf\n1XFJWvBzIJU/3KV6YD0KMy4CjxWUMO5sbhAMjvF2GbMq/+CfOFBTGfGgsbE0\nZE+S\r\n=ekD2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD4mKQ/5AyBOgldwMlB3bOiKTtqoaLUWFpPGPApojnUjQIhAKVrhJqrUFa1/k5akyNM9Q9s7BYw77lfyL99Blqfj7yP"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.4-next.0_1596910744842_0.9396546640634043"},"_hasShrinkwrap":false},"1.1.4-alpha.0":{"name":"@joist/component","version":"1.1.4-alpha.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.4-alpha.0+c0e53b7"},"gitHead":"c0e53b7bf5235a1cfef8a75d1c23eb27e6704a87","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.4-alpha.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-pPXS43UBAY3FEyOUub66uzmoeUxQrabfc8U9FKmBPcdgVnyPX6rmp5TCFDO7ULLICQ7z0i/uFQbWYvC/++sAcg==","shasum":"8e4410e32fae15d54365c1acc6285735cf15ed76","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.4-alpha.0.tgz","fileCount":31,"unpackedSize":29081,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLu4pCRA9TVsSAnZWagAA8zgP/jGBkA3yxH3S3xEmbOVP\na1WDE1/WBKDdWVkid66IgWPJVNcnooOfj10Oce7vm3wFSMsW2mIRBE/1ewaA\nbHKwmHSOJXg00fqU0dLfrSMN6Vel7sWTvT4glyx1yYqqLEInLNQW1w9jP5Sn\nPDuSu4GkzduecG9Dw3INk3P3mpihtY5ASNZe6xXRvPdMJbrc+KTJc8GmsJS2\noj1TTU2eYL2cx1IYY5rolI4yEYeZ+TJr1MvLOp+HFHeF7lsUsX/i+/Pr+Mv2\nKO437nZD5PUGdbPFzMafMICW03DpqYdPIY5GRErVCOMo7jX71Ml1h3NYSS6u\nMxSZUJNl9gxk+B9utPQ1lU1lkgNWFfbRgh3xG8CM6RBrrf6XcBgZTv8CMa6K\nh+QgOTQMq8Pfr5xvSUSLammiYXQ/u96UJl4pbdB/7DRtH91SRjj6MBXltXze\ntqE3n6hH0RjM8p6bakroaKKSuv03w/Rne+VYwkFA1OnI1wIVIVQGnv9RhAKz\nl+361hFrL6KADc/WhND7MpNSu3PjhHVvoQskOHRLrnoZuGFKB4/45yQmM35o\nPHcPGt+sTc2ruOjKd5GSo/GphWPFXBorDLMFJSsbu8u0/4V2KYjwPKiiRUJY\nXKcnqulLsQF/e5sOgMC6y1FdQ5sdxRHTO2AYQJQvHZY9w4fy1gC0bgRtDDGT\nEOPA\r\n=fO/N\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFKBE3gijoZWuibzGK53AeEXVPb6wZ+75J9+29ZI79qiAiA4yA1TYi8tdSryR2evdMIxcfXPQwP8gtH0HoExU0u6Cg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.4-alpha.0_1596911145469_0.7525945517013004"},"_hasShrinkwrap":false},"1.1.4-be69752c5ccf7fe8e9488a79e07630e213ba1b3c.0":{"name":"@joist/component","version":"1.1.4-be69752c5ccf7fe8e9488a79e07630e213ba1b3c.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.4-be69752c5ccf7fe8e9488a79e07630e213ba1b3c.0+be69752"},"gitHead":"be69752c5ccf7fe8e9488a79e07630e213ba1b3c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.4-be69752c5ccf7fe8e9488a79e07630e213ba1b3c.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-86T8c74J6gxPPAhqKa5Dyr1f3Cus9+bmN/Vnz8f874Sv/AEpIhr73mYFr1mCZp7QSOazt2TwZQt+mQUfEsj8ZQ==","shasum":"f3fd122e11d39cb368658f8570d4c96910e3f18b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.4-be69752c5ccf7fe8e9488a79e07630e213ba1b3c.0.tgz","fileCount":31,"unpackedSize":29151,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLxk+CRA9TVsSAnZWagAAGd8P/iQgFEXhdmTJCSGnbCRK\nxzFnwKoogBQZkNflkTvyDbQK7LvckQc8c6AgxcvY3v78gizJEehom4MT6IDt\nrSKRcx9s4vVwyVrzq1AX5asMfRDuQf4DjePcmwiNPOXI1rDBZSA6WpE0Oi9P\nXkWuCOkRmBkg03TAfFktyN9dQ0/pY79bOS9UmCychnML4z0KE63Sy5F6YRim\nHX2LNnbWuDq+kDPShDMmvQq4jmOuvHyjbQEMf7hzXZsvMsSrPgjyLHh3Qwxn\nuzBFUtk+RI4se8EDNVMXlJDmNMw2aDZll5mobRYA7n8ybB/hsHE+P5Ny9lMy\nAEfUtCQY6irQgRPkw/BrzkTNXbAtC9ObwTBad1GDlSo1ba8I4wjugqLhptzG\nlQA/JXMt5WMusvyPlBUG5LTcM2g9tebbn8ANqzF3pXwANmDYYYB9CsfZI9HL\n5digymB8AO4F8qE6PwRz5TOramqt45d/iisN/coGDexN51gOGP+Pe9kN8seT\nyFtoGAUP3RNhDnutSTTT8zS/U8QrUa/W7RXwuvKTLG4M6gqdZ3ksogoXwNvt\noP3bPFjmBgEoRBQLoHFKi3GnXAh0fOw6J5iFhvHO71d/QH2lUQ88uiRkHo10\nO7/DgZaEscX8nb4ozqeTfoZow0V8IfHV6QIhml6voSgh/d2nBzbFKQOKtubx\nkcC6\r\n=dAva\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQChuq2AiAq7nuBvs1ud3zY+2eis/I8Ve276s5qmxxKSDAIhAKi80yHU1lMIm0f+aVKFt46xY90IthfbXAZjZdc8V49b"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.4-be69752c5ccf7fe8e9488a79e07630e213ba1b3c.0_1596922174115_0.12265979184332276"},"_hasShrinkwrap":false},"1.1.4-canary.1596923079.0":{"name":"@joist/component","version":"1.1.4-canary.1596923079.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.4-canary.1596923079.0+84d2a18"},"gitHead":"84d2a186549a7d4807269c1e8a56fb202998e5aa","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.4-canary.1596923079.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-hq6cgNgoUdzVImmzBF+h035gKxG/GdlMiINwxBeCkxcGWuXlghMXIKEpSYIXkEMzVZvDE3ChYOwi1ZnzM4eRYA==","shasum":"cc8992dffaa604503fda641f853c0b67f993629b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.4-canary.1596923079.0.tgz","fileCount":31,"unpackedSize":29105,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfLxzRCRA9TVsSAnZWagAA/u8QAIO+nM8dRRHYnmx7sA1/\nRqrmUnXZHH/TDi7HzYNXwP3sGUkB/uGrJY/PulBURJuVW/OhcPfpxbdKv2VP\n77KehSfkjy7J0Xi9eNuJVru7RL28ljeCwJ9x4NiimQOwQhlE1cWovbGGgGCl\nubxfn41KkRopcXAfzPmJh970+UnkgHp8M6qiNZGovjOu+2LaaUAF7xFjPlIl\ntI7fgB3d25l+OrEdZrfFhdRshxYa+JFVRbURpQKhEan6kdv5HV24sDn/oSPe\nKOh1/2Nj2bAOYdZ2jT/iBkVF0WOolE2LAydA7KhrpSZcHu0DhuBP8TC0Sfo3\n0rKhkpevWpERyjvTHvWNIKs8aoPQkJz6C9LvtnEUkJAMvU+alT1Jp7sLVanQ\npXDaK2FH+o02qLoKdabd/YNsD3NkXhQcTP8Uu2m3JF4d35GUO5QUhsd4aK5C\nsYoIYs5QtxvkibYYHxzJdIHVFFdA5/5/iQyO9b6a0B2o3b1t3l0mQpEPY8sL\n1U1mGibDbWI5fUXXtZvo8MFgP/OO7mKtQ0DIs4SzGIJAaqHEN/bzBQxPMOgG\noCxKehBnt9qgpY3ifRBUwef19CF+GFuRVPwEQMq6V3cV3WwTLEuCdIItVjor\nNT4Ck5rTri/REubFpwCyEH8ZtWOty1kxJSDdghIxV9FVO2F726f/yjZnXoVL\n6wo3\r\n=a9y9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCugH+7aYc9kEZYRd1kx2YnNcsHkAz9SS8PmceRAq2zqQIgEMe6UjklM4slddOiBllsdU3rAE0wytRoFLO+LsOdsTI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.4-canary.1596923079.0_1596923089335_0.8450741297129951"},"_hasShrinkwrap":false},"1.1.4-canary.1597006052.0":{"name":"@joist/component","version":"1.1.4-canary.1597006052.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.4-canary.1597006052.0+2e3fdf2"},"gitHead":"2e3fdf2dcb04f35caf5bf1fe8f3dd0ac328def4f","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.4-canary.1597006052.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-LR8DXSQQh/pFuwGWE5NXFUu1GjOzkBOW7P6UzjyqdJ+zF86DBUmW/EWDL4gF6YpBAuaTY/XFEraCznKomAvglA==","shasum":"4de5728b15de85d7b8ce7c88e0b72c10153db44c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.4-canary.1597006052.0.tgz","fileCount":31,"unpackedSize":29105,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMGDuCRA9TVsSAnZWagAAQKkP/R1VdwbAihXt6y7Y+vK2\nqGHpJwGVjPpGXvfeDgzLXSqsZcdEKzRBfSu0j1NG/C8srM6y5zkpU38xVLQq\nlIusmjm/rd3k8sKcdYftv77ZDVongUpVcYRWPIiETgupDxxdpO+y7FOUraA4\nnuY8JfgdcXzunoKyDaATuJXf+XG/35NqxmYO3YuVSSH2aMHC75xudlJjZKHt\na5glA8z3OtmyuX7byNP9gIVmGhbrgi42SAiYVSOqS3diKYV1Zn+E01/tVpdw\n0fv1AJ513DOaMEeGWbMGMt+11hTeTZGajBTRWiqcIiISKUEiY8WkoPSb/oR8\nBKrDBqnpRcl0t+di8bXbBwG/o19ogEziP7wUHdLD85hrDGeqGcxqX5nc2P3k\nEpc4TnXaNv0XyrC/15nsx0ZlJt5xtiv+edFDdVt8a+HEOT8sL+jgnIeDrcgn\nmC1Dqc9a/cTvmYsZechkIwx2cgiwFAQ0ikAoAKgXGinY9yiFpb6HxVEC+5/3\nT1tB/NYDVByLeTb4IOrm2pPsn8OGJ9m09G5Hz/J0ZLX+1MYftMjFWzOBqYXa\nxVPQYSB0tGa+fyZL6MtU4hH5ggIA7P2zvUxSjFXroQ1ob8RwuB/JPErswD3J\nyZuiRTIT1Cc230IfD4xkop3oB8xt8KEgNhlzhc3e9MnhrIr+J3zrMNkFwMjx\ndaoE\r\n=VUwO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCBGFm7eUL+jkoToroJaja2eqcnnbNxWaOlFU+BpS3ZVAIgHqjiB4vNkup76TqownclJYGlvXxkraEWBViAmmJAVsE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.4-canary.1597006052.0_1597006061673_0.8049175446681023"},"_hasShrinkwrap":false},"1.1.4-canary.1597006752.0":{"name":"@joist/component","version":"1.1.4-canary.1597006752.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.4-canary.1597006752.0+de345a3"},"gitHead":"de345a308282435de55c63b080e1350a431df8f5","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.4-canary.1597006752.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-P/VgCGoSFRFSy4T/YTwDNrpKY3ykb0QnyDdQ8W1vYE/ryFTfO5aqt+rhVnsu26zVe90wcvncLHV1mcKoyGufPg==","shasum":"8cd8fbf37eb9d2dc778af4be78a6f3a044765995","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.4-canary.1597006752.0.tgz","fileCount":31,"unpackedSize":29105,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMGOqCRA9TVsSAnZWagAAFvwP/1QlGdhn2stTqaCtNtCI\n3vWT+T4UAFDC8bMIkh+3GBpmaz4o3PgBx5DUMGe6/kJlQRBBEWmuCZ2bas6b\nDr4K0hgwn5V4j5Y/XFCOqt3nDy7migR+4VPIUEpFpDmQF8jX4YHvyBoQvpkb\nsbbzFM2aDNDeNdxQgBl8ttEWr7ZoMjfZlNLZWWI72/cFC/RKBJL8Mkhwxz4C\nI673IhHOVPnHNmaH5dEq+RXmzXdnSioW7Ib3VZrO3uMKXJGTZ2oQvuswt97E\n00NJoZ1AI2snqjAZrPujp3423UZz6PklJm6uR0wxFSHac5NMuuDoUJ8N3VJ2\nzl23RMv4ca+/kX96HxyEYRo3cbH1Pk8KGc6oWNEzfUuHVPCQVXlKFZvB9P/u\nNgyLZKX5HLmbk+9DoH2IYwtqu2KlpB2wI4KAFNcxlBs+EljFgcgUu0EOiNMX\ngEk4f1rB4OZfbbAoAevDRlKdUEKkH7Ej3wvsGwrJva+aXEwdEFN05H6u5fef\ntZa0NiargVGmOU8XuJc6IoMbwIe37vDVvJYoGos6uLRcE16BDKDa3f0QJyop\n86gI7bUvKxjMzTgNCyJpQOC591eCI0PWgxDHDnseKaYKuCBoKCh0OZpQ77eX\npJ887DMIYo6xUYtSsUOrJqAbzkcGNJcbRagjTsIY2GzeSHqrgi3qs5aHRjmV\nJt5R\r\n=PLK4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDKcZDH2QChPf2EWfL2Y+TGIylWiEA2XVnLGQsNzSTI5AIhAP0/WNSqEcpd12CmQ5J/Zb9K1fsRMpTXi9yoKn4SgDFh"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.4-canary.1597006752.0_1597006761631_0.5050216713019133"},"_hasShrinkwrap":false},"1.1.4-canary.1597007297.0":{"name":"@joist/component","version":"1.1.4-canary.1597007297.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.1.4-canary.1597007297.0+1099bce"},"gitHead":"1099bce41a72135687e91654da7f91d69cb0fb2b","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property, get, PropValidator } from '@joist/component';\n\nconst isString: PropValidator = (val: unknown) => typeof val === 'string' ? null : {};\nconst isLongerThan = (length: number): PropValidator => (val: string) =>\n  val.length > length\n    ? null\n    : { message: `Length should have been longer than ${length} but was ${val.length}` };\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.1.4-canary.1597007297.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-AAMixqpP4SlERnkfMqv9KYLnm6KZevkpol3S1ZzoJdgiC25EgMWHltU3UBHASDUWHJ3J/+nIDoxBlghAwCjntA==","shasum":"6006ca7501c5929822729eb89e9d5a64ed874cb5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.1.4-canary.1597007297.0.tgz","fileCount":31,"unpackedSize":30678,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMGXLCRA9TVsSAnZWagAAr1EP/19N0RPzTyhZk3ulCtt7\n90K6K/rL3yyoW5ge6EMeU+7nl9ZlJW9KpvGu1rMLJVbXh+U/moxdIEJ7t0kX\nb6snndswLcx1MCY9u0gPhc3stt+vipDKjusC4jOgvD1dN6HmhCRwNFCZHEhA\nd/6cx6cBjnoF6bs1rd5Rw5QkSTYNQnPVL9D8Mx/BL9brnG2F0Zq2tIQH4Qe8\nxdhv7bD72X76CAqNLq9NYqfjcNAjzWvOwnpNgPswpxAVig6ZB1oIATnUjKGN\nne5VWckE9tjAjziij7jQZq7pqryJbsQI2FxBDPkMZ7gDwF6KkbaamArtZHDj\nmFmQLMDxOaxaeMlkliB6TjFVyuq2xw+dyVibyS6bY0JBQW4bohZSQj2fr2LG\nK2KmwMC7c+89VnLUjaGxQp6uDsp3CWW3tTHusNPkYd9xpcq7HJTOl1OnHkbh\nwrbHjS0cXQ7qHE2K0upHKiYAhd0O1cdE+01hwLT21Q29wA/L8X9jK34mvNcF\nm5EzFdlUrr/KCIQYrzYMIE4c6+KcW57S80oLwfxzp0ol1tHnRF9zWbHZecLM\nIz23xEdCLILWvkSPnc6MbsE44DElZZtpqWBRhz/Q7c0KL3Cs4vnjlr7ZaL0J\nTZSgnf8i1PbNUl2k2U3NFQKQbgz3FB0M4WwSlYbnv1cR7ByZpdExP45gq3M7\n2wbZ\r\n=36kU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID8aTkABC6kXCOI5Gl4+8Xy5wOhHR1vLgPt4gl7k1JfHAiEAgg5uXGLt87UyLZ/GyuS01gpEjHLvjzP7QqVrkv4h3lo="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.1.4-canary.1597007297.0_1597007306600_0.17458432295841497"},"_hasShrinkwrap":false},"1.2.1-canary.1597007506.0":{"name":"@joist/component","version":"1.2.1-canary.1597007506.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.1-canary.1597007506.0+ea98661"},"gitHead":"ea986615b780317863f5066a3a55b7ea117edea3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property, get, PropValidator } from '@joist/component';\n\nconst isString: PropValidator = (val: unknown) => typeof val === 'string' ? null : {};\nconst isLongerThan = (length: number): PropValidator => (val: string) =>\n  val.length > length\n    ? null\n    : { message: `Length should have been longer than ${length} but was ${val.length}` };\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.1-canary.1597007506.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-qq3dFdOxsTyiH5Akt4XeM2mcE44CHWtuTtAbEcxBn8o9ph7AdOobhVHZm+tpnwWs+KfNhlIg9nrHNvBVqwCbOg==","shasum":"f4656e059b65c6da286dc2286364ef176b156030","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.1-canary.1597007506.0.tgz","fileCount":31,"unpackedSize":30678,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMGacCRA9TVsSAnZWagAAh/0P/i6zD4GPADwwmP6CORuf\nR5D/dmGzmv5KZp60wZdZJKz4F8RD7wZyvkK8mxyoWrel7p/RstoHtKQDOBkb\nFPPPlqy/wZVuLdT1gfqE6e5pDD0O6eqLuGR5OYRdMwq0zLdzNwVnyvFTdkRv\nHE4wqGOAYi2tW+LPrQufh6JzdFGxzdnowpyUk/FcVUjGfO8OE87gKblJLFF3\n+HZ3zAVDckwfBK9RFt7m7Le0pr3pnFX42jlp5Yzx3LlfZE0DY6rhA2GhwYgm\nUOb58y37Lr+z7mtz1xmgWpCoHppSZp1mDtO05QcvuhpGzhW6gtokIYWbuQG4\nuIyGpeiXmv50ythi1sJvIFZA32vlcsBYr/Hf+jHv56zzVEiyYXY++WAvKqyE\nCiJGznIW7+egUDTTkxU4ETIowcczt5mu7xtrEH3O8gxxlWQ9mpEZRrz2uqI6\nj61MqeORog0XFEIOAa4aSHPYaMbhRlNMoLrNzmhFMsLqyOD/RZlFViZ9Jzv5\n1SilEqWDuTd65f6MX1471s/7VEVlNLtECNF+iL1KjXmzccA2gjtTqjIwKJME\n7CJnX0Aaz3r31omRT7NQ7A654OWeJO9aSNVvROQVgIlunyD+JWi7IvojsEiP\nVhVD3wEbCjudb/6fsJAJwLlm0Va7jXpzJ5FXTc8lfsTxVx+zdMupPZbEkMOp\nThpw\r\n=ergA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD2Yz5o7va8grZ34jWW12UO+zzTqMd5tLqqWoeQyZh5xgIgFhfLlPMkIR8gXsGJPCFqxL1FF6pLA8D2L+2F+t5t5CE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.1-canary.1597007506.0_1597007515550_0.2931402305043129"},"_hasShrinkwrap":false},"1.2.1":{"name":"@joist/component","version":"1.2.1","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.1"},"gitHead":"c7c44055da28c178e7d7b9f3cc62a75910e83163","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.1","_nodeVersion":"14.6.0","_npmVersion":"lerna/3.22.1/node@v14.6.0+x64 (linux)","dist":{"integrity":"sha512-I/7Msa78kjQKO/IrYChtYwbvMFNGjFyW40ja1qlzKfupExxQ9PraVZ2ReeY5AG55/BR4ELEh/gN75/Ee6QjmVA==","shasum":"edf6f259e9a51173da512057f8310900eb2133e7","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.1.tgz","fileCount":31,"unpackedSize":30622,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMGamCRA9TVsSAnZWagAAU8IP/1syulAAf/kikUlYitQJ\n/dc89lpu5jrAtagUuSvYM2YCjPB0LNSuL1xs9vNLGacn2QM/XsONMukaQwe9\n9JvQb/fQubI6ke1xPH+GZuxuvoAwk4ao7yzQnenprA1i6ayuwYHcXxBq5/Gj\njv+Lagqjf6h40mjOHizHEfwWKwoDQ5X67BsPLdAHI/d7eJY7gUNXXiupun13\nXMdf96U5qMrtYLp4+OBjVZFcpog/alPqDIkrugiIx/U8gqg5bi6KTm99kNyO\nxcL6zIbfpDxpuhsWQgO+J1g8Y9ql1OZo5slHaPJHQEmOpBw17KjCM4HFgcAQ\nXeHvbGP1YPP1bUwK3G7EZ6RRplMfqwf1GQu54Rcx20txx1AgWEpFURje86NX\nq9GsjbkQZWDp9aNjzUA6Jfl5CA6W0HW2HVP+Iw8mo7qehp6lWSuB7LYIq8+q\na2xjgAzVrANCiQuwby8SZaDNy0H7EA4t6AA83oBowIPdb1R91oNuscsxolQL\nOL1vCmqgwvTEfFZGyMQen3SbUpI1FF5xKGtZHX0ERAFaZ/KTt+Nwm9hi/qUV\nQOFtYvd4ev/CFQi1jUcy/UYnT7HMOz0REBKLkxCQCz43+EYbHzdb0irhi27j\nGye2xsrOJeZoPRnet5eSNqUozaW43APUrGVzHpS2Z6LIlwcfVytmdubXPy63\n0n8X\r\n=BOPS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDIkRnP/PCdmi7g3z0dOaU98gDvMrseg4i5BhTw9ZO+CQIgDSQNiQ4/HQk1D+TlxEBpTnhAFjCl4lgjOAwFRslEPoI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.1_1597007525553_0.2133513890648342"},"_hasShrinkwrap":false},"1.2.2-canary.1597007558.0":{"name":"@joist/component","version":"1.2.2-canary.1597007558.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597007558.0+c7c4405"},"gitHead":"c7c44055da28c178e7d7b9f3cc62a75910e83163","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property, get, PropValidator } from '@joist/component';\n\nconst isString: PropValidator = (val: unknown) => typeof val === 'string' ? null : {};\nconst isLongerThan = (length: number): PropValidator => (val: string) =>\n  val.length > length\n    ? null\n    : { message: `Length should have been longer than ${length} but was ${val.length}` };\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597007558.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-xkyM5fkOAWNFmmv0Wh0DEzOpdYErEr0rXwuFkd5IMqlomiPzPR1QhJAbleIsRjnkgyPV6ux6+LpNbSnD8p9Yew==","shasum":"30c01dcd5447ab1c72499b7159b460c2ee6c1355","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597007558.0.tgz","fileCount":31,"unpackedSize":30678,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMGbPCRA9TVsSAnZWagAAdMgP/i1EgrS1zADtvJ4lHUSJ\nzTRV63QbPdBmq3uFxJ3bFfBqSYXf5gLDdPXn9e9c33LYZtsbYckL9dJ5nNPJ\nDwElcIHqsaBYpJIjG5mbqB1jc42rwqSUsBczjWYPrZNXuu7IKUBS2lnezDq8\nPzsOjLqkuPJ6QUMxydbWklCUuf7oya3K0Muxwyfa1yQGLFBSkh6rciA9xNcV\nVUcxcHr71Ar7M323cZi1isxUAbP4CANBtaB+QhSkDZlISqAk/z6GrqYBJWk3\ncAjYC+2MBmdJTjQzvp2pxVQP0MLyvr7/oDjuiLLxg4AgKOMU/ex2q7SA3bLa\nfm/v/evm79mrdWkM1KTgh6z0nhyef5GdKZRl0ZNH4wSfDbcCTvdNEet6qSQy\najOmSYgmfTfpUV7VX16YPMKWW62jyEN8qPNthBE5vrRtbe5uTjviRxtiek6K\nkxISn0SA5Hp8+vyT9ImdTkUrrtpEbDWwAdgzf4Tm4p0ePhQ5BiuoIf0B+1w5\n1Exd50jjOCIPtsOhM3pky87S6oQPuqmK9XkGZKJcjW16zPoQ2DFLItl2MmLR\nqV+Xn6MEt9rbweeY5Xq4OTTJz9Hg4Q5nnCH+QJZY+VuWbs4tuNstfA0k9UNk\nSKu8ApIzupLzFwvWLlmiVhpsf9PYJfqtD9/rz9UfuK6ruaJqi6KPiVDvkaq4\nEA3d\r\n=TMUf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEhQRCc9UVqwI8gFBowWKZEUiyz+SPhE4qmzk680v36FAiA5Eq9/DmVA57+2myoW0VFzHUZNijTgk8T+1G/xf+sgMw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597007558.0_1597007567052_0.8208036153457308"},"_hasShrinkwrap":false},"1.2.2-canary.1597016555.0":{"name":"@joist/component","version":"1.2.2-canary.1597016555.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597016555.0+db09b92"},"gitHead":"db09b92d0d2b64b26f7272fc73041762947f7ad0","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597016555.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-3m1RIKG+w3D8AZVVkOh9cQpu1whDI4W1C2uHyWUQgIDI/WUe0jvCep3t65NlTUORF9OnD8C3VGVf82vD8CTqcQ==","shasum":"76cd2958bbbbf79382dc25e5b2946c56f5f79e23","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597016555.0.tgz","fileCount":31,"unpackedSize":30679,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMIn0CRA9TVsSAnZWagAA/CkP/1ORPwnbMc4oFirXGM2e\npPk7ti1MLorOTjdit5yDENhIGYgpqUJ88Ntq8+/8QKTi+pLh3AGkMIpoGnwP\nlSC2FxRIVtw+M/1HlPF4C0PJmOklkpsEKaGB8wCBcMelpZcsAO7z0kwCzFxF\nqqCx5Q1/I5ddQwLQf3U48+ZHY+MInO15XyTHQi6TlRkF++7Ch/0Pj4CWADLL\nYSjo139t35KWcNEOtoNlRrJGb1X4QiXkNC8/5EFMwBoDjtv9c3jU90fhfcvh\nIk2tg5vqgjPocJXLG8JXZrjaXEHV1KLDHG1528dQhEPjcBszpB6awXSakxLQ\nlUYod18cL+c76tP1YYam62u022QlugQtIPVRfkurWJDumk1VC2M09qI/zVy1\nk00846PKCW1ytJO73WKYB3wUpKoMSDwJsFY2TlZuZxBnK0LG9jGzUqG/ehHp\nLZYWlsRZl6fxe8CZNE2eApUJj1fm3phLyReQ5gARDYpYTD36SI+bfE5quAY+\ng2TCA/6GqOIkoVeSWPRDSU7x4nHt6Vfm0Nt6eIypwCIz5fkxA0GJJvXuOw3z\nd1DmX4Gq9on/k+dl6CV5HiW0fPznu86q7pDXAsi/A9rCCn69XWQfi7MTOM1l\nFSKbzy+uWzQ4mRshKwb8MoeLaF4O70mIzwRbgZWmPuIBGS/KWCzgyaLWYFqg\nItF1\r\n=VK8M\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCLwx8WKFVVpD0G9tbNuSMb0iMDSk29x/zv5SNkIXhr2AIgX2qnVAGCYpdIOgZydUrEIQkCu5dOBwNZ/fZpKZxcLkk="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597016555.0_1597016563787_0.7557230299319064"},"_hasShrinkwrap":false},"1.2.2-canary.1597017672.0":{"name":"@joist/component","version":"1.2.2-canary.1597017672.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597017672.0+f51343b"},"gitHead":"f51343bfb50c64304b5a0e5b090fae76c7448553","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n\nYou can also use Joist's property decorator to handle property validation and handle property changes.\n\n\n```TS\nimport { property, OnPropChanges } from '@joist/component';\n\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property() count = 0\n\n  connectedCallback() {\n    this.innerHTML = this.count.toString();\n      \n    setInterval(() => {\n      this.count++;\n    }, 1000) \n  }\n  \n  onPropChanges() {\n    this.innerHTML = this.count.toString();\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597017672.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-yUVQ3+qkbrxfULHnfWEbQW3JopROcd4m/ElJz5rYb628eYjxDc1bVGEuJfYOQZa1zALfcS/gng5Y3fmhkHtjCw==","shasum":"f48822c60857dd510f81db873efb54bf777602ba","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597017672.0.tgz","fileCount":31,"unpackedSize":31161,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMI5SCRA9TVsSAnZWagAAFbMQAIBHgpBJ4hV28L0juSCN\nn+DBNUKU6FhWmP0i3QNza0U/lr64Knp8fvVDiLL5Bkig9c0/qNrSvQ2QzpbI\nCj+rYpbPp2ErVF0h2QSswFoO2epWixW/8Q4LgoMW4O812Dd8m+Zy+vqvdMwj\nL7KHhFurPN2F8B9Jo6qFUNUX5QM4Ww9K/h9qqxhWb5k45OOexiH7gXDpf2+F\nJlBe4tXOupU65wxvYgDQYLSzLsWWC0y6pp2VmdxWZoFM5K5Yyi5xK2KEOOJb\na/E+rn5wvLNXRPjPFd8gdGPN6YXcqqggDSLRvhqXO3UWGbm2ZJF9qG+f9tOm\nEj/anViauKexwWig7/0oLttF+TPopAnGV5CcGhI3J1ZuzjBFgL7jUP7QMuPD\nLEnlDTlzPrVb3bBPaaQftUDDZV8Ukc4UAJwRIFqWCvDZpDFoDQwUuIfkJPau\nowR1iBvmXtmDe7uCYWOVrOPYcqE2ctft9xSZA2nRWsPPg1xJV4mmg+PkxISz\nrZfgYho/q69eVpP47z93yIav8SYg17RadjZUdQggRdsuxXn2QFYvGHzblxqR\nxfSlhYs8yLP4OKOZq73794lrc5JKDJLM0xM+asRf+kFXX5du0cMAxhHCh9Xy\nOOvQvBdghlLLdEcLYXW03UYv7WkRsMBsFF3eX+uFcfwkaE9hcRzgx5oUDc9w\nroJe\r\n=8O/0\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD15RikRMoI5iMWdy7dvG7IxFL40M7STs7LgEPn9TKEkQIgLprCXPGXPRZE5Eoh6BQgYy+VIJ9/E7l0gjl4uATYt9A="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597017672.0_1597017681628_0.37533397682193015"},"_hasShrinkwrap":false},"1.2.2-canary.0":{"name":"@joist/component","version":"1.2.2-canary.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.0+e4e99fd"},"gitHead":"e4e99fd6ff535c38e7ecd6660d41c619e0e16e4d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n\nYou can also use Joist's property decorator to handle property validation and handle property changes.\n\n\n```TS\nimport { property, OnPropChanges } from '@joist/component';\n\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property() count = 0\n\n  connectedCallback() {\n    this.innerHTML = this.count.toString();\n      \n    setInterval(() => {\n      this.count++;\n    }, 1000) \n  }\n  \n  onPropChanges() {\n    this.innerHTML = this.count.toString();\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-7SJvBUtkvnwNVJXYATkMZ20V3GYLwrBlXGSI4yNGWr3bAWTwT+r/DaXhIEq7z7KN6TQ77voLOHsCj1kFYrf2ew==","shasum":"c936f8f74de8be171964244a5f7d387b5923be60","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.0.tgz","fileCount":31,"unpackedSize":31487,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMMIGCRA9TVsSAnZWagAAXUIP/2COsh/nZxqqIB1RAsFU\nY1v1C3PwhWB5qvRDklflNsniLI/IXV8VOJ+JzMx5hP55WzM+/hQMnxRL31ki\nBTalrG497k8iVNTyQsxu3DHe1Bd46n9nFqfoHsladYGSdIa3xspMwrbcPnxP\n81gxOTtaERYyojHyOx+q2N0RyHIrE8kwvnJxXtD3xf5t0xVaC0lsJMYqZ96O\nwFq1PsIWKliVW/AyX8+gyxMcyH18cOA/rU9mwoFvFNOW9mJLbIK0KVUjOmhs\n1D3uyxqATVuyUZvg1okVVvqWg+X6toeqbfHBtQizJ/KDjkwU6pgtfjNxrxq9\n7/ljdVl4pJQQsrciZT/Zdi8bHAjbbq75PYlM+3xSX45h/4GVXg6KfWRm1OpG\nLn33O8MuyVyWD/WUgDzlIy6Ae75wvtHaEowf77lk6aFpLhyrdiNP4wQFitxU\ng/Ky+V3cHi+BWJGe3iVfdY6CqjTHlpCkzZRJ9XMaEr+X9VeJjTK2YhfQNI0j\n9hnPsJGBTci5qJQIrCXqdXwg8BED8Nx7VQwnjQX+4wOA+xJIf7W1os8Mab25\nIUtCRabTQj4L9DRHQoVhd/PIkJ5Gw7fpUqDC9MWwkhXlg+068GQZ/zUBJq8T\n7Xrtc9ItL3x1d2IuxSW0m/u8gifGj18FAH3evMgI2GyoZkvoKJTk3JKrYQ1b\npq5r\r\n=UDD4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCszHusC4L5hLSb74y78KJ59XmU8xxZiREBuJ+2wklWpwIgJXkoAbflZytiYvzmzh2bZIyDbX//m9vBfstr+NDCK8U="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.0_1597030918395_0.7802587363181432"},"_hasShrinkwrap":false},"1.2.2-canary.1597031190.0":{"name":"@joist/component","version":"1.2.2-canary.1597031190.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597031190.0+e17260f"},"gitHead":"e17260f08a576daca361b86dc0a77d3671c80448","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).toBe('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n\nYou can also use Joist's property decorator to handle property validation and handle property changes.\n\n\n```TS\nimport { property, OnPropChanges } from '@joist/component';\n\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property() count = 0\n\n  connectedCallback() {\n    this.innerHTML = this.count.toString();\n      \n    setInterval(() => {\n      this.count++;\n    }, 1000) \n  }\n  \n  onPropChanges() {\n    this.innerHTML = this.count.toString();\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597031190.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-HQpusmznFZqnsGlDHdtb1uixviJXjjmpjnAecGqq8r2cJvGelsPTlpb6Eb78cHq7tBPvWZHf5mJvNZpRsbuCCQ==","shasum":"c9066a16b655165e6c6e9f013408630ea6efad76","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597031190.0.tgz","fileCount":31,"unpackedSize":31509,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMMMeCRA9TVsSAnZWagAAoD0P/3ltus+JguA6al9SeOWU\nJXUtri7svRdWNJ+O/gPj8GMQH2b+Z7U719QD/5AEUj8A7tI9sCHeusy83Kha\nOh30lTid1pZ4F+QmHZjM8Un01h/1ZYuqp38xrNqJz3KvDUS986LtOxvg3szQ\nV4hNLOv9OZo5nTf+AG54mRWyg6n8XctEBBWyRHdw0Q9roGr5a5w4Fe/+4cbC\nhy48wd6YpVLegKWzjSa9t2ymZM4oXH5uxAH80aZLNmSpIKlm+Xt1e3WAoIUj\nH1T1lVlUuH7lvfINElOjOmr6UXUiTEFMm88cdU4u3mrgw87mXREM8QLZIHu/\nBKOpPmHCk7Cq5bkhPYnTp9+C0SOzS4sj3eKk41fsJXxM4IOkjARNswkaNfiB\nftqYjT8BhoiCXxeUov2yoamTL0NaR9YDvj3eJy4RhlLbeASfiiL8qtP/o+Gc\nLixkuM9BSoIUdr09jWG7ySFCyK7a6R+GyCVHrxtgjbwdLYXnvleInsJbfxif\ny20KNxEzKaTU+J1EO8xI9CEXaXGesmCnBA5ofykrESU/DQt3IpSc2kyPPya/\nppZNTN2eDndnMx0H/eY8+dpH0u3FJdhV7YR4Qa8PTWi4FfosC+sHrw9s1i3J\nZsbvKmjAm62kRhwe34M85/xpP/C92hiABEZW+f/duu9VfFK6CG9bInxhFBG1\nKxOo\r\n=qANs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDeTtaCVJ3l78qUNU9vQ4wbVNooPbV2xopmq2qyCvTSBAIhAMbu0j4biy9z6qP6sS+3JqW2OwkMZ1HEiH1Cxyd+lMoV"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597031190.0_1597031197637_0.8351878493951568"},"_hasShrinkwrap":false},"1.2.2-canary.1597065868.0":{"name":"@joist/component","version":"1.2.2-canary.1597065868.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597065868.0+e3d193f"},"gitHead":"e3d193f1875c19dcbbd378db45fe5ba0ce3b9edd","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).toBeTruthy();\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n\nYou can also use Joist's property decorator to handle property validation and handle property changes.\n\n\n```TS\nimport { property, OnPropChanges } from '@joist/component';\n\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property() count = 0\n\n  connectedCallback() {\n    this.innerHTML = this.count.toString();\n      \n    setInterval(() => {\n      this.count++;\n    }, 1000) \n  }\n  \n  onPropChanges() {\n    this.innerHTML = this.count.toString();\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597065868.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-tupWIEuEPf/ZJ8KWwstHdGxyVy6TQXn1AshYorUfxnrGkgP387uti/b5aKLu9zI3g24KV7FSKk++eBCppNE4tQ==","shasum":"e6ee1b7343ab76e70e62ce843a2f2b31799aec48","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597065868.0.tgz","fileCount":31,"unpackedSize":31555,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMUqUCRA9TVsSAnZWagAAXkkQAIMeV1q17enpjfEDUVoA\n93A0O4Qj2cFXn2QutI/lI8kcl89b3i6KLSmPUVYcDW5gQw1V7MpPZisE34T5\ncmtHLhQBT5CFxpisU4fxcRsz5rhySXTi7SsQoND/QbJjdXi6ueBPBfUwhys0\nMEKyybf+jNAd4DMpu3HOYff8EDtyElNyF8wDTkJdbmpPO7DZtAuVd07D58qn\nfkzSu7hxPZeoIA24kXk4MdcmaCCg+2QRY7J7pLzKLwus+ZyBhlMQ4Z/lw14u\n3IJK0f7YyxpKNkc0Ln35fFM3j1bQdgM/lSZ0D7M3tE/wTIDwrJGfPU3egf6+\n+pgkkPqxPpxjBfg9P4h1HxsP24PnHEQRKqJ+lk4Jw5stip8hOsWxQvz98BI3\nvea88VxmGWgPdFD7bFAO8hC0medXrvqfp/D/Dxw3kJEqRZcLoTPhszCfmQeQ\nUqDIMTDGAm8DwzL3w+EvV47soLMnD3qtkSyLp4l31M9FuQMNAaT42Rbdi0bS\nvkkaofZP5xS6I5SPxfyWDuiAVAGEsYvSBzjiZty89thZgIalKX1pSCMv2v0a\nBFdjU06RI7LMvy3AdUHPRmQWa5COH2rOiNvzw4iKzPTO2YhDHz7F3IoCRk8P\nWYo6JjZ73eBCeepnhQWyd+r8Jz4qBnOVR0YhrpGB/m6MHO5C5OnxmcvQlMYa\n1gkt\r\n=iTQz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHIWKJwM5lIMbg4NY0H8MRRM5WNJFvmB8pHHQRGVNp1LAiEA/1CVvkwCNDqm0dNbK3n1MxtkCUjx151yKnx+p3HMIGc="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597065868.0_1597065876227_0.5525645550841076"},"_hasShrinkwrap":false},"1.2.2-canary.1597065930.0":{"name":"@joist/component","version":"1.2.2-canary.1597065930.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597065930.0+f499232"},"gitHead":"f4992328aa1a4d5adf68ca04709dd0735db235c3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n\nYou can also use Joist's property decorator to handle property validation and handle property changes.\n\n\n```TS\nimport { property, OnPropChanges } from '@joist/component';\n\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property() count = 0\n\n  connectedCallback() {\n    this.innerHTML = this.count.toString();\n      \n    setInterval(() => {\n      this.count++;\n    }, 1000) \n  }\n  \n  onPropChanges() {\n    this.innerHTML = this.count.toString();\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597065930.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-IYGXbFQXOxWntTPfmiAWs218MzVvNrQ2tw8cVKqOk1zzJlE/sskGVPWVs788MwJz16c1iVN4pHNJqWG7ALWizg==","shasum":"e752d48efcf3a2d9658134a073c3a63ec70f7d7e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597065930.0.tgz","fileCount":31,"unpackedSize":31614,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMUrYCRA9TVsSAnZWagAA5p8P/R3cbegEZ9nXP75UZUyX\n62WEcXgryOBaI59EFhNcRsiYOIhwKGXxjIB2Ov4vYpEiT0Yrl4dyHDQrX4sT\n1fDOMjaKlHuni7Zs1JhAxezUaAwd0aYww+M7g3creR0N8OuahJ8QXRp2OArL\n4lfH0/t6wwlrk+VWQskMBrUDRI+k/YJ0cWco8b67sAO98BCA22MbHkFuHZ4/\nXwkjqI6H4gxPnab8ne45C2ToIbd8WgCaCbgNypiKQd0MTv44YoWrfQ9AUT5S\nE4ZiVUmSnA5e6gCRemOcV2XAfDnYHYDt6Gt7+x1RBZ1Cgi0dFDHJnRwCxrDm\n4Ya+rpaOePEuNL4JC8+8qv83Ng8ZJxMB9pK7Rl+6yMTOykoJhJTUydHFuyCf\nvQfuXj258FuIKCEfzEjdycQm8xTOJsfnX62O6KioV1C7oPxdNe9ijoWERRxf\njV/XsbctlcKkXR23pk7x7/7gCu8MJ7z7A3QuU42XyqtLnwGS5XVwxg4lpzZh\nqz9PGIx8kkEh+KG1XC2vWvZiTjG/h/1weM2trOs2OtJxCs3bWdoC2MLWfPmS\n05N97rj9ikvw3u+QdsJbK7Y5BYQc9BU+npReQ427xWMZEBKeprmuCzRFLQ5V\nupSA/1pTanFgeqBMunq3QrKd+0fkHEVUEwULMCSE/UCeN2LrBWh54thKodqn\nyJg2\r\n=Xv4B\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICI0r3PNppXs6EQFqHHYFwiFljKmcLU7hgKh+yKqbpThAiEArCSzwbDhcg4QSeu8M35A89oXLzUEqFUOwxXFXAKKp5A="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597065930.0_1597065944646_0.2823156900181598"},"_hasShrinkwrap":false},"1.2.2-canary.1597153164.0":{"name":"@joist/component","version":"1.2.2-canary.1597153164.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597153164.0+42a52d3"},"gitHead":"42a52d3e2a99853c8bec73236d59e610a43dd1a1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n```\n\nYou can also use Joist's property decorator to handle property validation and handle property changes.\n\n\n```TS\nimport { property, OnPropChanges } from '@joist/component';\n\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property() count = 0\n\n  connectedCallback() {\n    this.innerHTML = this.count.toString();\n      \n    setInterval(() => {\n      this.count++;\n    }, 1000) \n  }\n  \n  onPropChanges() {\n    this.innerHTML = this.count.toString();\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597153164.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-TvD71FTXUgIu3o5jbVwRPxruIqRnmqTQW5dBdOAbMPIAu5aCxs7aB5qy3x3pCHaaISu6vKj2E3lATcDqSxygZQ==","shasum":"b5deb9f3ab0959a55416833fcef413c3f32eed11","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597153164.0.tgz","fileCount":31,"unpackedSize":31614,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMp+VCRA9TVsSAnZWagAA/mUP/A/TcQ/uoO2Gqovwz7Mr\n8k6cTS1B/CTRK/4lVmevAa5eEKn8Z17W4U3aER9Ia0DlUh3zqlj8t9k4IsrG\n+LXoF/1UIEUQV5dZjKcjL9r9b+6LNYSDI5kkSN4fczUV0/+EgtxoCKrSPvUl\ny/eTUmc70LSR5eb4g4qFyoZdPFAELZM8mXoEaqoou31DV3QsLimbd8awrsZS\nHsQ1kxZzsz/OafOK5S/FO5WyDPNAY9eHAnApWZ7mYrEok9NWgO+jknt719wR\nRL65INz7Rr6L/fJ0M2z5vyXJPXJ8sahm7sFPY6CC3qXuIBHF0LMSBWvilSk2\n3WTuTbvoemVuqgLnwtdQtHELI+j3OPxTgdd3oEAuJ9NTFyHqM1SZYaakGrjm\n2FJwn3/EdEnQdenS758vBQ3lAoFPnV1Sk0VmRf85RK3W06fX1mpC9dQFosb3\nBejidSAVFZ7TlRLIuZYMmuicmBm2piaLIwrtYeq/gy2e/BfFEXKwplZlqphM\nsyjuCeKZ5f/xyiF1fA6NmmGJ4rcJZcfYZzOc6QsBduRVSJqCoJzm8O6zFDil\n25O1pLzQRzlwASWwxdlmqEwgdAQQw3T66bf9/DtkLZlq1xE7IfZqLvek0Dm5\nUVNbSd/uLbsmxWTADho98254EVNndaXsbjSrAc8W6/Vy4dCUu9y/j/07L2+j\nuEbn\r\n=5BzA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCj7+7gnhgBWDkrPnvJrpro4KsT8Defy92s3rT4WNpVbAIhALnukGhf81DxJnIcTRU+LjXaCyojcuh25B5p8jpSHkA3"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597153164.0_1597153173498_0.14711573106489362"},"_hasShrinkwrap":false},"1.2.2-canary.1597157533.0":{"name":"@joist/component","version":"1.2.2-canary.1597157533.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597157533.0+c88a773"},"gitHead":"c88a773a99b02a71deba9315f788bd11484803ec","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements,\nIf you want to use the Joist DI system by don't want to use Joist components it is easy enough to use vanilla custom elements or whatever else you like.\nAs long as your element implements InjectorBase you can use Joist DI.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  private foo: FooService;\n\n  name = 'World';\n\n  connectedCallback() {\n    this.innerHTML = `<p>${this.foo.sayHello(this.name)}!`\n  }\n}\n\ncustomElements.define('my-element', MyElement);\n```\n\nYou can also use Joist's property decorator to handle property validation and handle property changes.\n\n\n```TS\nimport { property, OnPropChanges } from '@joist/component';\n\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property() count = 0\n\n  connectedCallback() {\n    this.innerHTML = this.count.toString();\n      \n    setInterval(() => {\n      this.count++;\n    }, 1000) \n  }\n  \n  onPropChanges() {\n    this.innerHTML = this.count.toString();\n  }\n}\n\ncustomElements.define('my-element', MyElement);\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597157533.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-U39+jPATJ97Q67OJUZdizvW9TZ9xCN1Kfwk8elZ/h/BLBg2OYtNrJ9qtNnHy+XaSXsxVfhyW68J66X+3psThQQ==","shasum":"568c2d7376f632a514f47ba1b316fe519a73d88b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597157533.0.tgz","fileCount":31,"unpackedSize":31712,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMrClCRA9TVsSAnZWagAAHlwQAIUNTInDCD+U41MXVm2Z\nyaGyd6RibXNgtPbhBadoLIWnXAjXbSd1+z24c7R34un2PIjky4Twixz30cbW\nn6mRVqJu26N5mJKWm10KOYOIWhqDwq2kGt9VSRhdOww7LcECzM+8fw5o8pQR\nv1xCXHjbYWJiCI4CfvGrzDKieqbzmmpiXkae6OcWlbsHZU4Uv6YSyJMYLMWz\nrPMCav3UVTPii+HapZtMMopwySpb1fiTRE41EoW5m45wnSapkgKDY4SyORun\nqpkHwNaLGdBNUTzSd7gTGUZCGromm4gBcyuUsFDjClwjjImD4Nk1+TIR9U5e\nxM5s1zaKimSUXqc3o6DRZ3MIHIZAa9qkfU4eHnKZmD9l24Pj0uk+E7ZFGn4z\neR9SK1mxlt4faGrL85w4fDyvyXqy3MopXGAvPyQUVHqXlqjs4i57k1/jEsA+\n6Xvdc9oV4ib0x9VuzaQTaIbSC08XtY7LGeupSHlj6Myjmn3OyfHK3Dypyx0i\nKNwsC66XL5DpPVfrY7NzeTGONJKvxuah+cdLJyc5IGXDEuoOX0+VrZTxWJQn\n6jhAzj+b7Ja3dfPF9vw8VqgdRm0QqSThXohP/ab1qS7DZUj3lZIozoW14zlq\nRCLD3qGC2dl9XBZunyLiERxvjQoonRmKJMP5RDB+vD/uxfyuP9w19DXgUsNP\nOFaj\r\n=PtCo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCQCiyHhQcA7vJNYic6df3d/43fvbq9Utkiy/Mn3I+h3wIgX9Vd0g/sW5EWiR9FkPsijd9/Lu7TZHcfsmkcz0K1HAc="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597157533.0_1597157541126_0.5891943912896458"},"_hasShrinkwrap":false},"1.2.2-canary.1597158866.0":{"name":"@joist/component","version":"1.2.2-canary.1597158866.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597158866.0+12a4768"},"gitHead":"12a4768ff9dea2b36a8fbdb26c005fea378225e0","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends HTMLElement {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.renderer();\n  }\n  \n  render() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  renderer() {\n    render(this.render(), this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597158866.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-hqTdmib4cdRCNNSrcYAQmgDJknJdueqbp1uGS647rAFcGi5FDRUs8B6bBJ8INfnAU8Uk1qXsxhxMRjEl+fBuKQ==","shasum":"f75f31f5084d0d4a47315fa0f82fadf33afd49f5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597158866.0.tgz","fileCount":31,"unpackedSize":31584,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMrXbCRA9TVsSAnZWagAAXAcP/in/nkNpB3bTrRpKccrY\nqSR5VRzjHVHNwC/s+KO5KZWIcl3TEWE36WpstAB8dANSCdgVhG/QbKypNIGN\nhJfC9OkRaW9lDYEj9ocapsV5GJZvCvUp4SrNwE9C3sfJUM8OgBhkWKvfhYUO\nmDWQudNmkGdHg6EowjL7MxpYFpy4k1L4ng2aKcgG8dX/9jVeEB/XtsFhVZ2m\noIYRcOvnvTqFzmgwe4bRbJTmHvhz58VJZui79bugnMscWscrOSdDc3xJVnpU\nZK/BFmen7K3bO1m9orYtyKep4QZ5ugEGfMNUx9OJz9Nik99Bf9zUivN7S0ra\nbPRaKUb7ug3OiKE+fkF8Hfsf8CGvCsBHpD9agMXukP94NfkQUdAVgeefrxz3\nwivv20h0AXFycya9xW7dkqgzgxLb3pFlsxYEcrEZ+kjI7zbxg/WRb/zLGtIE\ntuu69vBUwfCuMJJ1SwsoO+CDG4nshiiLSqOm3o++qxPwOTGmkGdSoSGrSCNx\nKHy68THpJZVhny9eiRb8VRvStblvAqgrzGF+ztJNH50WGKNdzTc3CtB//yT9\nx0s5VRJhIyjpMM+UbGCz5h4wF7GmLEo/Z3H+1kObQvE/ZjtPgsYeqgSkpctW\nYRc6UlArqyibBMHaHQWn8AYfwScEOjGYWU6odES2RArUCYicdFjqlaTENC0K\n/dMs\r\n=sm0u\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDLMhXEpdHFllD9S4c4hM6AwrK8Unlo6g3U55tLsqhAaAIhAN1HJWLIlEIOta880WE7aZqNTJ2AJagMdR5y1oOYeByX"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597158866.0_1597158875309_0.14491983873137926"},"_hasShrinkwrap":false},"1.2.2-canary.1597158927.0":{"name":"@joist/component","version":"1.2.2-canary.1597158927.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597158927.0+a7775c3"},"gitHead":"a7775c3ea3c6bea5013f7e03112f260e6df47d31","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.renderer();\n  }\n  \n  render() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  renderer() {\n    render(this.render(), this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597158927.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Dz13PUbixwIPSnaWvt0A9Wfqb8YUuF0B6d41tE1n9D1cUTbTPKHadhrAa9VvR0tZkUIC4AdilkP+dnvihFxPyg==","shasum":"e28301bb080d91bc559ac91bd37d8ee30ddd8ba1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597158927.0.tgz","fileCount":31,"unpackedSize":31598,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMrYaCRA9TVsSAnZWagAAV18P/2Vk0ij5c6OXZAetIeXL\nwFSILD5/KPZSkiGX3yOjZybDsPXX0xPFJ54HEBf3+uXsACXs+AsJTqqp8xHa\nUMcg57EYkawbI3mBRBOA8ckdfo7FDYbyVW01kCo4GNJuLWLCN9Aoe9awXyKO\nw0R94IutIuJhGdVdIaAnQOGmSrLcte2ZhnxvA+QyEF+4Fv7mpI6kW3eZYmW3\nGoBCLTYxiA+Si69v+jCvPZa5FbVRBQLyjRjJYjPhEqN0IT15SHjdwZCHGi9m\nlJ8KjC/qImAfnCF9jJsITXqmKgKYkDohNJ53w02y+nQPZvP/ka14jT8fzriL\n3vqEWL1Df/v1UcntNe4qBEyYAkxoqt83Ga9GBc+Bp/2dsFKkah/ferGM/LvE\n+447ixEpxYN0UsCcCkXASig4/Yf3mTb1ma5lrXo7mg1uC6YUFg+Y9It9ymbj\nXSR11Ne5oSEyNTxQ7DNAaxTmTe42AO7JjATNZdYCas0rilorXikpkcZIqc0I\naZrV+tTZHfhcxQuqYhQMbASrGmMK0zIxtg42oT6bZNNZRjAUU+C5okkwGvl6\nNj5fBURdjuucT5PGdv3bdgnFvleFkmB1C28UuG2kdZUEQ89Ki4DPCMb1dnHH\nyekCDiS5CmXHjG2F2hoHrCXeUU8XV+QjIDTpMg6Xgk2sUsZ06F7ZSjNvqalD\nBOIA\r\n=a0qz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICr8cehxFhbt7NTucuW4Z4briGYE2hIJVrbBPlZax5U6AiAWpCywWdpI+ADRu29CLkcMw/hgPeRvoVKiA62wE93Qgg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597158927.0_1597158937848_0.3903557506264941"},"_hasShrinkwrap":false},"1.2.2-canary.1597158982.0":{"name":"@joist/component","version":"1.2.2-canary.1597158982.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597158982.0+e1a7e24"},"gitHead":"e1a7e24b78afe5c3668b07ba851882e7474473ce","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.renderer();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597158982.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-NiVz1WLLXX3EUTMvQseUaIbrdeMvETThWXcBKZrQEvlVOVpw6WAqoFu5cqrUTm0U9BgmPOi8CREM3Zmn9I5LKA==","shasum":"4a5b432190e14e8ebd7ff61ee26d491dcde73086","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597158982.0.tgz","fileCount":31,"unpackedSize":31616,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMrZQCRA9TVsSAnZWagAAoBsP/RqtRjpTA9HBkpESbWea\nAVzucJrU2LN5FxJSIfoJDPmLyLe22U2gbl/an2B2Ng3Cw1jXVxVimunYn32O\nzUn8tNPqgy0B8atfCZ/xrp3C127mJwIs6IzumDur/D1f1Bt1ewtUcX2dDkxd\nYX25cGNT1iIF5Bty0X0acb1m+vveodQbAezeybGW/OwF74FzK64Gqe+7FhxX\nTHHsVvUDsd1ecbdYBEFobB+JLeig59Bc3zBAPj/bIoE/YOuXlkAkP4/W13Jl\nmxzRovpYYv9a4FcYya7pmPcZhmYfIJJ3lKBww7Kkq9Cej4aGUYZBfmogeAUW\nj3urypjNXJ0MsctCX6XV2b1y0pvB1qUHbtYESJqtBE+lQ67VTTuEMf6qt+vG\neAg2nbfF7ReFroW+yn6lGYGz42eg334qCQ2EJul52iZVptEUVZKMBIGMxUPf\n7X6T5TeaKh24NQEC+3mDiN30Hz8MpE2lEtAlUbTidArxGl2njlaj0mIyWG50\n+xIn7p3SG0jz7lqh4Q0ZfuQiybTgkb1YArEhDxET4NMccxA9tJfIcD116oTd\nwcYcHIJEieoHOeGg5MvMrIf0Jyup+l84HntNMJA12iFFINxMzqaP/5K9vRC/\nYi5R6DZ5ZmZyReel9biKRpJbrjLYE9s+sY7FVJ3rPyr084W3WyIhFvVDP5Nh\nYQai\r\n=UH+v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH/k8Q6v3ToUmTOr3m81wM9dB7CoapiRvoU1tdSzotlsAiAZUOWCVLYj35S7tz6Yvx4+ZySo8mBT6onkJiVUZVEwjQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597158982.0_1597158992411_0.6824038459755823"},"_hasShrinkwrap":false},"1.2.2-canary.1597159017.0":{"name":"@joist/component","version":"1.2.2-canary.1597159017.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597159017.0+2c989fe"},"gitHead":"2c989fe58c288d58c53824c04e5834e1ea1847cc","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.renderer();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597159017.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-4Rt5MkVI7iIYcr21C0kSbVVqHJcEaYTYVShuFS3rLnXchfRSRKC0+a9/2ZnyXcLBpd4nbLBLcyv5SEPyPibSzA==","shasum":"763e16178860ab51fc7664f243e6667a4f2bda78","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597159017.0.tgz","fileCount":31,"unpackedSize":31626,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMrZzCRA9TVsSAnZWagAAwZEP/3xZu8v/SUHN0XUmJptU\nYmX71oXUYPMwpQ4IanOPeE8NXoeEp6cdeRLpCP6fBe/oWyS4MiRPyZa42Yqq\nL4lB/jWqitdDk3Vnl6aHFpPhd1YmIrmhubvMvnKFrhyTaA650vtBnR6mIBzi\nHLkAHp3/GVf1/VHd3wzWBdGbH8hcm9PAc/671qAlyKVS0Kr8FSGGj/Qs6tbo\nTQG5/5z2km+JsAxRVvf7xBcVUOeXdd/SKc/4XuU1nAaof772j+LIQAafY5G2\nnHZm5KVDp4L3RDkimwjNJVLxIuZXfuMkmDQN+VkGBeRAj58oT/b3xDkNHni+\ntFB2qH/LtbUwJy2oo4CheJNAD+nOtHhEPMn6zeZ9mnSb4ba5f5T0Hi4mKEYY\nFDWULz1j2o+i74zDm4JbTNoRYUU1AOqF+DRkdiRINJcmp89JnJ5JwDRi3+fr\ng39vs7+UbttaCK4DB62HQjPvrLxhDA90d5jnDzZy5j0J+LTeAc7X7RWYsDSD\nc+EzQ0bHkqQtPYFcHaR+5PvvMrOASjxBSyOS3DIOtrXOGo7acYkH43MIAsur\ntE2QtX5liehHRsxtqrMmB2s5okV4CQk+Kbz9jsWRPY+8sQjQ4bROP/uTsAJa\n88+exsp/ldFsXUJGCBRk6c4MEUSyE6KrnTWtsV61R4vfFnqSFhmF9yCAhoPJ\nj4pn\r\n=XmQi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDGS4uC63TohK00tsTATKYNwXc3avhpRQHSiYijnsZiqAIgKJtCI7KkD0iPHvzzfbnqrJXJwJAcEvcWsDMLtPjTIkw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597159017.0_1597159027209_0.62727379037866"},"_hasShrinkwrap":false},"1.2.2-canary.1597159271.0":{"name":"@joist/component","version":"1.2.2-canary.1597159271.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597159271.0+34aa54f"},"gitHead":"34aa54f88b8bfa0ddcfd8c0bf5dd131e094607ba","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597159271.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-YGyL4ZfQ8y9mjAIvo+pO5HlKZ1CFMpFbG41uWqXfo/w4DkJ/0l6LVpsDos6aMq5eVwW8yfpp2X+7zVfVC90g9w==","shasum":"c98ef908808dd54cb9a0896bb3c08fa17001641a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597159271.0.tgz","fileCount":31,"unpackedSize":31624,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMrdxCRA9TVsSAnZWagAAp9cP/RXyOj9M9qF9QQE1dwNb\nXDdNtiLQN2JAfjFeExlBYTd0zvaRXeOuruuIDxoojF2Eq6l/tzizOlfa2n0W\nB5fhmTEdxPL4eT06xUOZWy1lRG0PEMDpR1Qs0XLfKH2UN10yXVlp7dZV/w2Z\nhnzaBUwTkXWDmF7JCsOAAarzueeO4T7++c6WitIBp+iyTOCBP4Xcn1M2EJwh\nCVqh38ihZg6gtDTtLLhAPtEMUxDBxgl/2L5jhkM+ERNOhW0b23KHM2Dx8Apj\nQm9LELR8UkbTwaMxafJO9qx9igOkH5QzGgVLsBU5KFjbfRUIUu0Y+1DZcCEq\nVnebT9SmTssURZnhRksJmR1dj5DxVgfNSfJ1sXnkr5a7Dcdy65vbV0vVXklH\nI9YpGz03vP/YfIvGby7zsqvSX3oa/g26KVZCXYajzp3k8lJa/jitWdJY/YAu\nwV5yT6OmeL62iXplb2dqEe5BEOj+XgpFKUwAyBtfLh0vdGBOYXNoAF1r70M5\nNGQdZoTmYEnMAUep5b5NSsEIHte9QjrBObyKktCGWmkT0EmAe4qOMP6+1XZp\nii7jZVaFtqMqaf+AjVD2DHpx3vbhGWmMmwkFfDftPJrf1a392GJ47Bk3maEL\nahgfI4Ah5CEwVw8iUZmNm7euW5AvleFyAcG80vmx3/K/8VdMpjPzGA4loIr9\nHi8f\r\n=m+cl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICSnCVe9T5njMCw1eYpGAFO+OrWdCAfeQ46/1vJRN+HtAiEAg9AR/+rn7xKvMxIj6SCtASgfP8K+41NNeavVn56Yf7g="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597159271.0_1597159280921_0.7285149772225217"},"_hasShrinkwrap":false},"1.2.2-canary.1597162545.0":{"name":"@joist/component","version":"1.2.2-canary.1597162545.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597162545.0+fc00bdb"},"gitHead":"fc00bdbafc754bfe87bc595a87ca5c17f6bbd2e1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597162545.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-khXTJSwrwTgPGxHpfcKnzEr2AEyTsz/BdxoIPx16Hq8LvFDz47AW4W+BOD6CBttlFdfezKsL7VdOBvSmff65JQ==","shasum":"b4f5d7364c76db48f5d48746bea738a0795b6ed5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597162545.0.tgz","fileCount":31,"unpackedSize":31622,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMsQ8CRA9TVsSAnZWagAAVFsP/0qAe6H3ldgxjAyVbQ5i\naZt9nd4/e6pwbzcYqWYEscDYaLx9DLpvx8GYZ0lkGZJEK8lR+zr5EPw+hfBI\ngOmPfhhEWFQmJ4F3hCpB8AY212VQnp19pE6gWDy57jo3n3oKI+1k2cBv31Op\neUPwlVz2jyqIXrddRX3/qzybDZ6crXTgm6qg0YgdSYUtf18E07bNlww9SBr4\nVl711VTkeUgbKkroAkBKur4vcliiHq9jI0q8hDJI5/naMDjElHnGePyeqNWA\nt4Q9mL6iKhX1TMkXbgHd8sVVH7sqrn3EYpu99E82FBG63bACggk/uIMTWnrG\n7gWbRZ9zKGEFQ64gxArNjPZfGBoMp523iCg+og/2E+mEhtVUsg5PTteXnlbv\n/LBdVb0NL9jJVLLZ7OkjVnNN1wvVQAkf3FwPyN6g6HSNjkJAGfczV42y7jNB\n9Hq9dTfzs6b6tddTnqTchQRjF3taPok0XJzfk4LlTzhkyYSbxVYBVzcYItna\n05WU1gBLMjzH6yo95p5cWy1IZbr+grbRWB6HPAuyzDJ0HrF3fovD6pz3QtfD\n2DL66bbTP4NeVMIbFvgIR+RTbst7syxyJ4AOB94LcJJXguAApZDlk78BtFbT\n9QvLJ0Azc1+5Li5DpdUIqMwyJTQ9m6MwZ5tqN66Dt9RHMQdD4yYlyy7vTOmK\nFQpC\r\n=R3VB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGnBrpVwNasSubYxhCxv+abTVg7aWKRV2IWlPqqC6cKWAiEAuM2RQfkhm/z1cst8vsc8WzR3FYI2OUTP4QT2I22bjPs="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597162545.0_1597162556138_0.3552021098897593"},"_hasShrinkwrap":false},"1.2.2-canary.1597170842.0":{"name":"@joist/component","version":"1.2.2-canary.1597170842.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597170842.0+c4365e8"},"gitHead":"c4365e89bd4b9bec2a73ab1815dcae57559fa797","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597170842.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-9cyP1Wr/UOSh+Ajk4WOp8v+K93cwF6MDXL8pTWPhTafGQelmo48P5AifGyjM79NbknhVISBC7lO18qLZoeujew==","shasum":"81b556c608466375adb2de955afa7d812366989e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597170842.0.tgz","fileCount":31,"unpackedSize":31682,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMuSkCRA9TVsSAnZWagAAnTQP/ApTLwRHcsq7FJfs5yg1\nFCcpo5GjJNfAUbNs4zzOwWztKzMm/FkSBt2iquNzl1sUN6dEq4nXMs3PKMeB\nspfLmX6sEXOpwGIrLdezLQKYghhlSINpfn3zcakuJteVaXtdtUdkGpOmQy3y\nSTdB/K9eRFyar1TomvU/yWe79/1bl/h96UzD7DfN0ZWagFmHFb/R5uuqebNe\nVgjh68pzxOWLGT/EAK2vlV+40Y1VSrLhWqjVjzDMi8KmWuhl9yKlmYBiep0s\n0NV+z32SmFQzrTK/j+5I01+Pjoiv9PVQfT1c/ZMgMxDTlXMvHCs5Iss78/sB\nLSAoTYHwghETnr0i9XQw+WLZ+WbPR2GIGZRNXd4vRBmVKY2eHi9CBNxzEPkz\nNMQ3vrxovihE/dViLWjkyaYSi10YaDB8fFWAy5c1wiR/gwoiFArsHH759B7m\naUgKniy9QGYgX60JXo6KEjIdIsKfg2WgewmKqhjqKX05Imuqq/NuPDv5BZk4\n5EtxNPaykqlBFb/3zpU7oeGRtjH5mXeFjp+w/u1ff/jn+IdRAntV149KSwCg\no3+jDgu09+NCz5VB3Tmm4SfwYxv1sqhLeW2RCBBMMx8DSvnbZndWvimTxXaI\nEVjk3z+TKsKmXwylwzM4NgJrEnWjv+A5OYh3rdYrA8SQOAKb0I5TrtlRyC1J\nJoBH\r\n=eszC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGcjdia9lYcbvKacLoPyhHh5hjjva7ue6r33iqHIw42GAiEA8Km0c+baIpxIk+F6SjTkltg/htywwCLF3iMoyLl8+H0="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597170842.0_1597170852051_0.273610338062263"},"_hasShrinkwrap":false},"1.2.2-canary.1597171698.0":{"name":"@joist/component","version":"1.2.2-canary.1597171698.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597171698.0+6f49315"},"gitHead":"6f49315e933d3edd3c1356541de09a63463de438","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597171698.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-IUsnbqTrkMtPeCZs7t5cZ3cOIYGma/qAhY7lZ3+nL5gbb6qqKMTxsMm100NEXHm+fYu2WgVP65hNpCFU9m3z8A==","shasum":"357f30a0644b353ba9fb6544146eed4173e2b9f0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597171698.0.tgz","fileCount":31,"unpackedSize":31722,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMuf7CRA9TVsSAnZWagAA28wP/0AMBHUodZYVAis8uva1\npsQkI3eYwN2rtwCtLtSsKaDeEyhjz3M+VTIU4Vimg27HHC1WqGZ74B9hdby3\nO/NQcTCxaRqLXDLH6rWvXUorE4ilcPK5Z0AI2/Q+/RATzimauycEmkO9itGg\nwyzRPfOyHjpWebsSmaQWuDEOSldsnto5tQUiak/QhMnjawH5gNFtF6auyOtx\ntFQtdC00pIFmDkvN2VjPr1cG3ovV2TbW4fEsjYdqQsBDMW8oZBmebf76nwUs\nWlvRmxrMT3ypylg8zsz2FmQ4cMV6nkQlpBAcgf025kXP3hihDowCY6O7XADi\nN8PtBSdKkOTGvT/UeAa85KRuoodYSMVzlfQPjBcuSKXF+zdQksALdTePKtPO\n6cXMmGGc6HxUm6vkyTVrV1xd7OtLXPn4jObRDYRdneTZBCuqnGFlW/blsbLD\nVnKn/n8ZfHnWsD4Z7j4aRJD70QuIRzXUC/geM/k2y9dQgk/eZdAJ3e/ERHtl\nsbnNS5YFFLyTQMb+8V9ZUQ8eOL6zqgTBCVM6n3JUp8HrwpQ4clhKyjh3IJJU\njO/r3wV8fGJd4CUMb6ostBvUOd+NQfuIq0bLq66GHvGM06g5x8A64GivUwVZ\nSHqXPX/N2fePKtsDskmJVjtL+h57XbzkjQ7XUvVHkFDGNZywnDQXkAvkWnhF\nqppJ\r\n=eBb8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHYzV6qEbW8wxpXq7rqQeivDz7SNEDT2IKy9jLIDy38FAiBSZSwQfF4Pr1oZyWByfntRE/QPbX58JUKoZwIDZnN/Jw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597171698.0_1597171706884_0.31732307562026296"},"_hasShrinkwrap":false},"1.2.2-canary.1597173679.0":{"name":"@joist/component","version":"1.2.2-canary.1597173679.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597173679.0+bc996fb"},"gitHead":"bc996fba44f080ac9ac019310cb96005e740325e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597173679.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-UYkiEIKAQzK80fq+wcphxnoxeUXtL6BF/E4FeP0mvWi3krHiHMiagztKgxbWbmMVtaMowN/soaAIBzBjMbmE4Q==","shasum":"2aadf9628a3c8059b23b89816c6c7132140f8cfd","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597173679.0.tgz","fileCount":31,"unpackedSize":31660,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMu+5CRA9TVsSAnZWagAA764QAJEtFXarXG+FnXL77Qnh\nM24n/PpP0nAZ5OVq6XVOki81+SOlUpO0o+2E01NxdpOwVE09lXZFE18c0UIQ\nWt6fHjV2vZJN50jwNuBRLNksBpNDoB1e/IgpxSMFdWZZSxWQ96AowgRCJN75\n88NcsGJFKGI52OfaPoh2dc9kRTJN9OHmmt2jeCO7Uv6QXPG7vE+FvNJwes7O\n7yOaoVZiofWEaYFpj7C7kKy8TebkHw8xapeG7t4VgTM4YlQxV6ljgAiY9S2w\nu90cVbVZ0rYIWFZ2tBBxRCGGuWUHnbKZAnzuZ9l0ozczx5uO0JY+mnkDsLoZ\nNuTJNgcvOH7yoiCFSz3o2ZJZU9WREgAbX32fskxWP3NINru8bdhix2cMhLtq\nn+dPvnOxo5OmYFlSq4RA1d9LkAGF1AZRo3uJOYQcX2T4o1Nj1y6HOde4yM+r\n3HJtH3rSJp7N8bORn+mJfwVE2+FDFJDBBSwWNjB2/jwEtrSygRvySZjrh5vc\nOvwMXJQDVHTEjnvwZCn8rYKrXyOhGkaztYmbd/C1zqNnXrlG7Y+3xDh95laK\nYtvm+bUUC/7ssiwUoaJsbvz2ZNURqUEEiHvKm3XA7DtkmHv6mTi0r7mndFxC\nuBJ0xGw6A27FM6px0icfMKBxNjkgU01qz97uulqxgls9dC+LbkZSB4qIuq2E\nvqSx\r\n=p9or\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD36RV/55PKOl3vJkQlaSQEZ7Rlw0ZSMExa7GpZeTBWtQIhAPjoG1qzKCI8JD4VwvB26yxsb2hU0qcRE13ooC8c0MPC"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597173679.0_1597173689123_0.05876388731730575"},"_hasShrinkwrap":false},"1.2.2-canary.1597174225.0":{"name":"@joist/component","version":"1.2.2-canary.1597174225.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597174225.0+de6c57c"},"gitHead":"de6c57c5222a5da2131bbac679c6be5c329e2b65","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597174225.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-3QtOg0Hp0QkyGW3EnsdiS8EJstHZaxdNCl3DVaRAjliWwrenfqn42BsyHdBbM0K0ojYWWg6JSKDHd6KBZ0c4WA==","shasum":"523ee6373fb186f6f57b52dfaa71cac64aa53cf2","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597174225.0.tgz","fileCount":31,"unpackedSize":31660,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMvHbCRA9TVsSAnZWagAAMLEP/1tlLN63JsVHLCvJfaRQ\nrZOwE4GQJR+XWw2vQkPv/0PKyHyEBSk3F8YjW9HMiGNyxBIrqAJMlo0oR7hv\nRKDGIZQE2yBhzDu9V0Y5+Ye9D0W/KlJY2mAq+mC0rtIMWXzowJV5suGCHhHS\nxo55vsWw33FnZVX1RAHnWhCMZNBEpfFBluCeJDWYf2QtMa6hm5HXk5RAvf/P\n1LGloQL4YLgYkWG3ZWUVGr7lY7Yt8BnKUOOaeCsYzLcnRLmbP0cOueACZptS\neEyKWupfXR0KpyqlnLWtfv1awAAfTiki66nU+pdylhVUxuDwwfW45QYvq/p2\n0J9vwkTY4jll2+abwfZZc81qSQknbXMzj7E5kUk8Q+p/wUzSDV7wrRT2AJM7\nealqk4utX5ltIKiQbX0gOvrHqNzEY/0PMvvgsLXB7AXRBEMgsqM1fLGyIpFu\nXijnB81dICQ1QFf2Q4RfBdyE0DyGNhe+UeFFeOXlbeSDIycCRjfutfkO2ae+\nN+r8bcs20rg8Be31JOkpNjJXoTK5DCip3V9a4vqj3ZkUijiHEwVAgX7TJqoF\nNbMvkdJPR+A5sURh1hYd1ZJaXTzsfTHZbsc2qLuof6sWhMPMkY+uVhIuhyHg\nhLbhQmIDgs4ODI8s3O/0zme8WCnXKS4SW/PaYOXz8u0xVW4KhkTyp3WIBU5K\nz+AN\r\n=nr6g\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEMuhAdDvUeiLb+rAAFgyVLJGTot/RjB+tlgnwhL5RrDAiEAgg+WU5JnUTX4a8I9R2W5Ci2fvue1yKyv8VcuIdJPy3A="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597174225.0_1597174234775_0.0743716215303385"},"_hasShrinkwrap":false},"1.2.2-canary.1597176000.0":{"name":"@joist/component","version":"1.2.2-canary.1597176000.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597176000.0+2570e2d"},"gitHead":"2570e2dd52238370b377753a1e713cdeb605681e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597176000.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-zsI2mZhO84giLNzgDnD++6V0n7c6q4luifSO0IeYy0abrf7PTXL768pNjIt7abJ3SF7Fmx4OhuAUGU+DsdOhpg==","shasum":"56c205127c802e572be16663474bb5c12b8f01e1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597176000.0.tgz","fileCount":31,"unpackedSize":31660,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMvjKCRA9TVsSAnZWagAAV+MP/RzsJ/OZ+5m3R0tvvMpf\n0r85CkzCGjhKwcWnvl+E4frHRxAqVfizqJhkY7XbjCEGy8qK/LfJdddF4u0T\n3ery2EPcR65P+uuq9BBblIV9fEa4wGW/xjQeh0L4W76d9gR3px9uMpJr4jaP\nkYEMKneOGHYgyubcX0lENNaxe3OdXmPp3YLLuBsZPVhRGUktTZNiJtExWQvh\npez1KJ9KKQ3eKtE+eCzszyvslA+JB/iat6ltMyCOZ0+MpCaSn0FpjDNPRssQ\niWjQpXgRXjVAdzKk61cEFjqdCV6n4OaCqXvZN24baznDWQx+KkXkHrXV1fLv\nrtSki/HVUzheDmVjsKbVFbBeP1dXdbateTEdv8xVVQlTYbCQNwP7aZzTRLk8\n48/YalW+mo/jvd2zoDg8X5uLLugYFCEUxmVztDs8UOu1kDnwuZDxtdnPKP7L\n5EhFO+lYItK8gxOG60K8qC07Nr2zxoCI52KGBq0hkN6+xLYxZKuaJP0e62sA\n12/23sylIneQ0NCOfq4PcQPrwXO6m1aAtCgjAH9yPCwmMpwLdY4pMi1VyIXB\nvQq/jdlYuSEgN2IOSMuZB0ialDN+RYvwu2q4AvvpKg7M2brqYg+b549XwPoC\nQ+eHB3jZlaWtCH8ZH85WixaEiFvXseneNpVmokcqoJWSIDe0cXL/7TPBm6Vs\nqKsY\r\n=vK6K\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBiCBoP7DngNsf4FCH7CuB9G3AV19kFlMa2wyFamm1mXAiEAhf5b7gKcmquwMg+K5DZPym+48b0kti2YH5UBJBjJa7s="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597176000.0_1597176010289_0.1517903471605795"},"_hasShrinkwrap":false},"1.2.2-canary.1597176081.0":{"name":"@joist/component","version":"1.2.2-canary.1597176081.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597176081.0+5c2be9b"},"gitHead":"5c2be9bb974a2c3cd3fa7a1d6e765e9e6dfdee75","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597176081.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-D7eqq8lHDdmtvGeoZoRKZMPQiJj8HZfIQCvzCLzWec69xO9E62AxOWtL7uTLgCYYEJI2J3Anux5PfKcvK+eCsQ==","shasum":"925e283e1622d2fbbb2be0fdc93a0572aef9c095","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597176081.0.tgz","fileCount":31,"unpackedSize":31660,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMvkcCRA9TVsSAnZWagAADrAP+wbnZgHeNhbwR+GgQTKm\nPJutQNFQw/c0Nfc75nSrhkbyJxVGcY0VLgq6fbL5QBNYmkbHwiXNSRI+/3db\nAhC1E6B2Qg45PJLjAfVr7XjY8ThJA37PykseLGlz8ajNAFe2HiATfdlXC3eV\nwBIlT1TwlHR6CfHLnO+jWZxU/Vj/rCyILzhFr0uu7OcpegRCSmErk1WOnZ5H\nugTWV+BvTkq0RUGBIvoBX/i6A6664L4TRZCnIcU4Urjy+CNyVsQUcwj8W+za\nCyxgzfXhmYINJFysKIpCK6A3HVvHJw03BGN3hDSHdZsvKU/X7KzpvWfxho6i\naEmAuu++GSFc4uW0SU5P8ya9vELTaJsmRiabKYFufwlZK0R9tfW+dDvYLKKQ\nGtlR96OTGe0jvhRn1kmZ65HzPVLuQN9HK4NcR6uvk9QXjhD3KrtWWpwbpdGA\n6mgYdYH/Eu/RcJMlKNo43aiSVuFF126aNpuNdiRRvL48KqrvztSAT4tA8Qy7\ndkF0HZil95NAJ348Y7rtTX/drNBubycmHLsavYwyZ6bXbD84yz4z6HO5b7dh\nZUJ1FtOqumL7hHuxlvcsNCRKG0RIEwqPGdbDfQlnJsNR1EBN8FUYwMBjzHwC\nhSZDL0/2mxvAHFmNkfUTKx/+EWekfkbUmU7amS9uVXJ7D0Pf3JTCIhxDztri\noRwD\r\n=+/12\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDhD9mB7PBSpovOispe/16cemP5G3OFDDtbxFvussxtsQIgU8+UJs+hU/maKmsWV/OyFIjnoTLUQ2dxafRLdk87iTc="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597176081.0_1597176091903_0.8774976732858539"},"_hasShrinkwrap":false},"1.2.2-canary.1597176297.0":{"name":"@joist/component","version":"1.2.2-canary.1597176297.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597176297.0+f8a2720"},"gitHead":"f8a272062f4d415a00392072ed22545e7bec8ce7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597176297.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-JxcdAKNyIPiDCaRR/bJAsA+kCVhuUkStaUrMFeaIwzlnBQZ57Fjix5sgeA9ZHczwbI8g6l6JLp8zLSOtU8EnbQ==","shasum":"d4d26e04986dd32cdbd5cb90f77ba283f800336e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597176297.0.tgz","fileCount":31,"unpackedSize":31660,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMvn0CRA9TVsSAnZWagAARfgP/2FkHfDD2k6t2Nea1crn\nYthTGAT7iQsGCig3NvfHpRtOu2N7EB/niqD6h5sRN1F5rM1phlv6+QaklIQf\noH9y9vQs4YubIQgJSEJ5P47Ho/TQMmQqBZF3qRB1qFYk2NjjV7CV/f3Fggou\nCJVC+nfqcZ+oFvwaolSQNr3glFGvp6R1/KKODjxWZUec39QAKGVZ43CjjKrj\nb2veH7lY+fuFYkFb6CIiVLhTlTgXzsRiiPAG0leCV5sEBgQxDKqeKLVG4gca\nOr4UzYAGDMl9Pr41ZhvX+zzqJzrYI1BpdO8MXQwCXF2Oro2EI05CqVuJqRwC\nd2ZJYSHx/6YZB/SCtKq6KaGmkP+yPnCvplKjnRIH3lnoLJsSLOlCQX9+KlEF\nj8WDnjOMIcKJrxKi5TND/LdFDnGstdDcAju+Zxc+8KcrdzHDGAAe81Iluwuv\nO+oe8g7/AvQEvej6Ql3eLqfUpkwcAM6+ykDH5DSEd1t9l+MKnUItod5ZJHCY\n4O+hck2y/DkVPKYV0en6upmFsFu84yyAgiQalRAnE4SEywx5qqfaEWQCW2NX\nnS+JvJu+C9qX6MBeoG+x96SDFHtw1/QZz2qA9Y4SMpr9AKnuoEVgpIx12gH9\nqSX/yTlNTT0ChwDcwRdTP5dCcNrLukgVT47vJp+HPinp+OAbXkTraTl9v2Oc\niAG8\r\n=ScGY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEb/mShLyONboI0trT6QLn40dfu8tMKfhY91X57eu6A5AiEA3M8qnObHsIuLdRbnLy+zcHhxMmtLgYpPklsKd1uP8iE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597176297.0_1597176308564_0.30380888397829175"},"_hasShrinkwrap":false},"1.2.2-canary.1597176632.0":{"name":"@joist/component","version":"1.2.2-canary.1597176632.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597176632.0+a5b467e"},"gitHead":"a5b467e67f88f830c0cfd6cb182c921f38461a6d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>Custom Event</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597176632.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-grNzb5tQblAl7OYLonzWITyAYKxHxr7SoS56s1f7a1FpL+bdysk/ue5m10NhKkCZZUt3toSJ5kFaLzdbn/DjNQ==","shasum":"e4994cc8b0054ef844e2a5eba849233656666059","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597176632.0.tgz","fileCount":31,"unpackedSize":31660,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMvtCCRA9TVsSAnZWagAAg/UP/AlsznOskVP/Z0mWqX/K\netqM0wGPjvRAeIxVD+kLx6rjf6AD11f4kXQaHgh/LM3bUMn+x1HJMKpPMyhF\nLnqEHXBY+6sHzs4LzD6EMH5pfPGHBsi/SC9A1r1osBjbaZLPpRWfdBj4lNeL\nkQGxU9y4//F08GehaZ95uXzPt7/YkrFYF+3g0pBes/u7slqmXasfUB3nOZRj\nk610hdarLnL3PjfcGxc8jwJLaEBVcGhC7iSdwq4Za7+0cXRFHkN+oXm5bhqn\nvitd7jmi542Om4e3xTEYTuHhVmnKr/hJbwjUneCtecMzHEQWrF86GgGiFzMV\nWRwswSFFRbwKVjcgPyVY6cf6T4Urkypwx2ARJ9KXNCqQnhxqrXuWnvaQ4FcL\nWOFKvEBzdC0T9ud28l6nS+mCkl3JDvo/qxMHiieBM1CM95x5+bYHOgOFfUPa\nS/fDJgqW2F+XOwkfwjLGZ/lPzcX0tv94lTEi4bJz7NfbFyNf3ImV/OqxCeBU\nDER6b94Wp8Kc6OTBqUTxHaPbTktKmkyZid3zbJNxpqA+TRlACKPyOVZr8B75\nUfwYJw0eePI7LxfukgAO9v/W4xuqwNO2XBuep/AeCpn3XMr6sHYrpnqqFpHh\nmxVFznODuzsIPt8ImZJQu73tDnF4LkjEUWePF8ZPOk1V6po5ILJqkg8RWndZ\nRu4J\r\n=6tP+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCauu4ycvHyVEcIWPMV/aACu9dud2ufu+XC0l6iluSHKQIgPSRxvBE4AQtPcqHpy0XI82s+i6ZcHMzN3LDvfX6Jb28="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597176632.0_1597176641502_0.5721648904333301"},"_hasShrinkwrap":false},"1.2.2-canary.1597178849.0":{"name":"@joist/component","version":"1.2.2-canary.1597178849.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597178849.0+b0e9a8f"},"gitHead":"b0e9a8fdf739ae7855cff9e322c2cd90ed67b505","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, OnPropChanges, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement implements OnPropChanges {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(_change: PropChange) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n```TS\nimport { component, OnPropChanges, property } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends HTMLElement implements OnPropChanges {\n  @property()\n  public count = 0;\n  \n  onPropChanges() {\n    this.render();\n  }\n  \n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n  \n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597178849.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-swMBfcgwWKrtHud8XbkETCBU0oKCGVeRaeSXPSYOUb5TZpNBH89MKBsECZRttgR196dZlv98dZiLmPZfLmdOBw==","shasum":"3ba237549b74358926e7e1a1255cc02d669d33c8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597178849.0.tgz","fileCount":31,"unpackedSize":31676,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfMwPtCRA9TVsSAnZWagAA2+sP/iFr/cHN8Earlp35jvoY\nAxwXT0DYiWriLo7XbP2vvk9MqexwN3airS//FqCKH4bMEQx9M+WsFCIpiFSO\nUoZA1TuNLdp8BtDJW7AIyHj/icTOon+E7FT1O0DTrXok6Wns5jrFInasQGqC\nprUwuay1Zqt5g17qkJCjCqhbvZWjGu9oNpQWlsFQ2AbPFts8qRyYmJrQfLyT\nITu/iZN7zKQVtYjBLppkG89dHmq2G92ggJd03hnX17nIvILUDlFMv7WwxIE+\nmx/P1kmZNDBQKTzVepdslOB7jwEgGQwwQW8I9g20qjo/Dasb9rWiCFWwvrmp\npPWxt7tPnyac1fk4DrDo+3+HTLA/uyruO48EhATLeDC+lrwLU1DBlXW0/BQl\nSYaX9YrjKSFogl3e0mvxwULKeSLfvZ8yWkCsEWX5Ga4BPNm2dXQHKfUjwMzv\nN5eE/9GnLFo4ewoW+kL+UAXU+tbE49hjc+W4WUzgrzC6FprVMn7lTZojJZvP\nUTLA54MN8WeTg9wyK4FZb/aVactiFBH8ttkX9960FPxeT2eh+ZiOIEtTF78b\n+1hxlB1haRrPkPaI6b/kS28lZEUeAZcZ14IJ6zbIviA1gWHH/xtBixS0JCxo\n3LkNXLRCeTDEE8dsqm3sDhnmSPUlP8uiXZZwf3R885XlszGDvzZCuknzlzT/\n8cFM\r\n=fpZm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCypwkBQTlsU5p25aMjUy0ZMnnexZ/Vgq1lG0JQnULTswIgaxyzCPRwZUH8CeFR1asovpNWhJcdQgyC0othOVOeH90="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597178849.0_1597178860674_0.24581985989469368"},"_hasShrinkwrap":false},"1.2.2-canary.1597236972.0":{"name":"@joist/component","version":"1.2.2-canary.1597236972.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.2.2-canary.1597236972.0+4b87d5f"},"gitHead":"4b87d5f2eedc4c26d3ceb23bb3b5024e0e572757","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.2.2-canary.1597236972.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-PzYpvkeacbsH+BqroHDAYS5YPezpseWatND53mFHKtYPOzHqVzmmrSUnFVBTlU02rDncIHh/DzofCtASYYL9QA==","shasum":"f0c2fdbc4353ebc27c35bef27b05a55479e9e450","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.2.2-canary.1597236972.0.tgz","fileCount":31,"unpackedSize":34961,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfM+b2CRA9TVsSAnZWagAAbGgP/15g1I79PBHKKMkSo83h\n+DZXohAJDaJbvXhS6FyL3VrssqYHSFZEWkHcIMQFMHOBb/VskgbJrToQXKrA\ntdSWohNeYV894TOH14enL0FsITROIMPdfGB0gPhwa1/Z6eB7wdIcykVfh9nD\nZ9byZllnfW59GiGfMP5QUTkFgJnd1JVDaeRgmy82XfxqzDaKWXH4uOs9aCvV\nY+RasV/nmMFCgUJcddFmVydcKL4d5T33inJSK+R0tn9/FTP6WS6shtiVjvmH\n+E6ntvC82d0hemN5BexqrbXqhr3NUnlRnqO2xhAnKnQZqoUfiwb8mHjB5+pu\np6oZwhwLI+/KObOmX0A4kYBO0kzYdhs6AJ7usauWqXkpFHNFRi+uHAgOw8Hb\nJKnsmfLRQObwmEDjhDs3MkAThIxt3tH5xDUNCOFgCMmLxz2pR6OXR7sSQtJs\n0hQtbcBsHFfLocyk8Fk5drrIMGmMV97pvwtQwEyRm6ltD0DByyMDSHNhs646\nPxiDL7O+bHyNefa7Y3C+9El+p0mLx4SGwEU5IE96nGncGyPXMuYVlgrWxh8E\nrT+lefCxE6p3d/bqwLuBt4PWLvFguI+o683kMVb03OVaxv5bZ4+h6cdWNDoV\nnzN6Aywv9/cqI5HPyiHG4wm9bQ0fq5+FvExIRM01+7XymlAerpWAwwLBPtTN\nyt9C\r\n=m4TI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAk7YKWZJXxN0aQbQ/QlVRCvFXAY9QYMPeH4orTl1pm3AiEAkvXNQrffjOZ/rLBqN0YJ9EWkHOL4aTZcn9IoJ1Il0ME="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.2.2-canary.1597236972.0_1597236981826_0.7255333646079083"},"_hasShrinkwrap":false},"1.3.0":{"name":"@joist/component","version":"1.3.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.0"},"gitHead":"2da15903d1b10e926eb2e632c35bfe4d82a53955","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.0","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-Sr5Jwf2QPPRAP+72btoUQosO23deGd3fIRhFex4xgrza0VSSTPmtyZ4X4LX1mbigv5TF0mLVWClignjQ2jB4/Q==","shasum":"4de1b220ca86ea11b359ad96db1b204b295004e6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.0.tgz","fileCount":49,"unpackedSize":63550,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfM+dJCRA9TVsSAnZWagAAL48P/3rbmJMvVQc/YiPTzKtK\nbii5Xa5CYjWCJys6ph5ClWjxTrTLTAgQ1ElX3Bjst4BTlPIoGjs1XVHb7xIg\n3f+n959iU7aYdKXcQwYTtPBqVkGfQOB7+KrekQqAvVGL3xywz7qb/tk2eXSU\nCeeQ2fBgSaTcnrwgGT91h8AFYuUua7nz2FHrJ24U5J27HL+u+wPGL+jtEI+s\ncmMpdSQdzVm7a7HUzflDTB6KRwgXcJvcTAAh4klRyzH6Rz3pkmVj7ICNBU2t\nX+5ghmZLUsC881LDhSrtSNyZavNTH4qJRAkE2oxuhTz/cDns6IbnW7fyICjH\nQHz906OBlzHK2gXzetGEaZFha7IeZAqUJ+gb10HsidIQhR/FfMfVGEtWpmVM\nV7kmSEgpIADLUJycNLY9teWSwldb7O7W8k/MxeMYJxIpOmeLHggdcUB/qhgQ\ntZLrYgcCA/iOpJeD17dVurlkWFouLROYFlecl9WcLSroI7KVSUZVKjriIoPv\nsnapP+YEssZJrmtB4HslgC2tUtuRRGXcgpJmxjMMwvT6rLn9lpf7V1kqOo5J\nYPpiwvWFPswxOGWNHLSfWF0A4fwGn1CTu50HOPkevnXH9r9UKDu4R4nOs8Wf\nmpkfWmbio8HEUydN5Bglhqtgpnx4MtIWn8kHlIED2FEIOl1dsl8YMX/KCqdO\n5Vtf\r\n=NFMo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAmasyrHI0GHFaJad+8Gq3Bd3oQg1lgsTQLbqyPwIko3AiBKih9UUJHiLvg/V+iaWjXdUXBHu79IxVnXLRb4Tc4oOA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.0_1597237065561_0.9192802361355967"},"_hasShrinkwrap":false},"1.3.1-canary.1597237092.0":{"name":"@joist/component","version":"1.3.1-canary.1597237092.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597237092.0+2da1590"},"gitHead":"2da15903d1b10e926eb2e632c35bfe4d82a53955","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597237092.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Z/4peKXa8uQQYnJWROOWE0/FqA4QB6sql1lT4WNPtd1agfvQoyQByFfyP33OKMmt6Q/t9bTz4aUuA4fGy3YiNw==","shasum":"981aeb68897b3d2b65dec38a0e3d4d51797f0634","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597237092.0.tgz","fileCount":31,"unpackedSize":34961,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfM+dvCRA9TVsSAnZWagAABekP/A9GvFbbhKuNfWNU5GGM\nTIysczmMF5JJ3omtkde0l2Hcn4rDW791rzXCIFsiZDEhLBWljo6hOJiAAgNN\nFOv9V+6CEqQODNNdjU44u5jzgxE8IaSfqqmcL2OCyOrB7sW9dznTC5iLBaNX\nrkS4jiNkRwKIzNwdnV2scVuiQ1WnlrEJOtAr7Bu8XLcmo9G4OAbjsKxWib+l\n90sUWJG6vq7FHUIUxIqz0PekavKs/6S5dmgENvd+C/HqCvs7YPIrDg9DArN6\n1ArU0Hk5C9Nfn+5V4EMlopGbNEWrtKyMAKXZXWcrQ+AlpTuM+Ar1PFB9vxXi\nc5VTvD9czsh+V7H3D3CPX0ETS8Xm8fTTDK5nb+ZTdZG2idahtCbLUm3HoCJ2\nuEiJGoHi3VNEsRE0il52TK+qE3fFloCVcEHkwTPjHNc6XuJzu8DqvAaPu6yJ\nnW1MXk2WJvPJEylxuaumOsw63SjWmwIPshwGL1DmwsMjiguHzJ0GfuwJ7p1v\nMotcs45zoVh7J3Ra8X/HZhhGHD96eIW9wN1+phVTXyrV5Hjw20kAxGjt243X\nGcvdcU0VVM7zgLOIrKUoE9g4nw9TzUpTOKzum2dXdUHCDf2iGHb7kORsqdGD\nReBNf0UdAM/RTgbseLlvcBrqLHIojoePlfleaVR/WVSIjsduP76CwLXPNjnT\n9wG2\r\n=asax\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC6LM2lCOOesZEaX0VlXk3M3WPZFot483vUNX39/vbVgQIgQHESa7u3lq+Qsxzdm7ZKRQqI9rrPBw6Ld7Fe8PFCr2g="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597237092.0_1597237102718_0.9031952687465741"},"_hasShrinkwrap":false},"1.3.1-canary.1597237988.0":{"name":"@joist/component","version":"1.3.1-canary.1597237988.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597237988.0+c86ce8a"},"gitHead":"c86ce8ac7e9bf4938e582e362711d94fa3c4cbd2","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597237988.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-XszD3Eqt9e890RK/ob3O9ZAJj1V8RXH9hlXbOvG6y+ls3R3xXAmgz6sjHUl9l/FglD2K6qgAmv2mibxhZ6OLEQ==","shasum":"c545c2c671a8aa6aff1dc5f8647ef29dc029a5ff","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597237988.0.tgz","fileCount":31,"unpackedSize":34977,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfM+rtCRA9TVsSAnZWagAAIRYP/RF0cPyPTdawSQJqMcM0\nwrBGY+f/G6pgGwBUmsved0GfVItxN+lgiyIvG/CTiS454HIdhdeDXV89RMNQ\nlCJa9FTVu0a0ZQg+szRE7zHxG4lZK9cQUCm2Jw1ZyiIo831wHUqcIgPNwFA9\n45mV6H0xOs/zrQy3/eq5Qj5ND07mINkBWFEVMMzlc/0Vfj6+4LbsXUgyUow4\nC5Lf6gkT2EF23mVnq94yP1MCR9QOuvjj21q0K1Lz73c5irnUrOwdxQgh87O4\nC/ghuASdG1x4RtH/BdeiR60RjrhDSEcfoTAPnsFCRXWkZAHyQn+KfzZzy9Jg\njXYPz6FrQNW/naQ53MhzK3n1kO+0dUTedJLDrfROG7BDWZH3BL6wnh6vsM1J\n4DAo9QjrTCRtMV+/nSS/JmnJT+fyIWMS3i/nEMZvJQtjeO8gSdgzHBs/xnkx\nNTA95X7QGZ+XbDG3WKX/G0GPl3A0oDAsUfMKPPH40jxMO3hCOakevE6l1Sce\nF28uneXuMEZHd2rLAhK69uxadM7rS+IcPd7BzVBJn5U5ECpZH/yeJ4qCwbLu\nxuhszgUihF2OnJUUt+4HP2krtMlaTgCpQ69WijV5s+ly4pzRWK2bsJ3l7V5O\nGJRW1Bib56lmfc7y5rcOuabydn5676M72sfDgpkZGYQ+7jXG4EV38f68u8iF\n1I2l\r\n=01N5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDcA3poenUM344OfGxzN6DYRUhyYyI56LcT2aaQJr/uBwIhAOneqgoypMBz0YEcTmq3Fsrz1cTAnYY6mkkC/dqYF1rh"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597237988.0_1597237997444_0.25911358383576766"},"_hasShrinkwrap":false},"1.3.1-canary.1597239751.0":{"name":"@joist/component","version":"1.3.1-canary.1597239751.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597239751.0+d273b20"},"gitHead":"d273b20529451866d7e0b2f71275a76eec8562e3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597239751.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-St+FsYAsQGb/zJphOYRVeztCAmRQZYOiRm+FjdbLS16t1lDlBy8pf6KwcuCWr+zbghpeiCbuks4d1s8a+a1MOQ==","shasum":"fa0a7ad3c3401d86069c9ce732f050a26a15ad8f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597239751.0.tgz","fileCount":31,"unpackedSize":34977,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfM/HRCRA9TVsSAnZWagAAYiUP/2gCwfyShzcRcQDaDdX3\nAML+vWYHHqqLbRGQR38rBQxfr5iAHtdxHbDsO3zB6ZEumLXJ6ZRA0NJRFs5D\nGhZj+e6iV/NDS3jODkvZAAJ0MW0er0ZGOX858Tk+eL37+qMweJhJ1D5W4Ee1\nhiEOkXU83csW9h/HM1MR5CEqtKeEOcDRQwUvOrT5RlQ1b6yPY8YYjVcfRq1Z\nvqpodlg4Zs8A8uDN7/sC4sfJZzu+cZdF9vjd9aM0LV48Hblky4Hvbp+wWiLN\nI6an7K1EKze3+MTt3sVAutYsWy/sonCYrCT+j5TQKE+Qp3cE+kfk67V4YLz9\nUA7DO36yvUjYsCERfw9T0d/Tv/50jdTZNyOrJna6GaV2k6/5imLqu4bMHCr7\nKg5D9nPQkeUbnXfSgHeSn7ZRwqUy3nGpwxXzMex+kD5cC6x5/0Fkf8bpDy4w\nIFi7fHUdukepmUNXhVwSZAE8eE4WXRhi6JC/lJt9hJE0toInMlKxxnl6Htf4\nTCYbb2NKjlax0v2KkYXTJ4pAHEUCBmHPKUIXAr1UR/MAy8n08QjUzQ8YcW1Y\nhB/ab+V1DqBitl1CPCa5knbEzszuJn6pKZ/Qhpxfm1WcJz5NfGp9aWvT82X1\nGp+EZNeAODl/wyeDo+IGAyz9p0cKSbB5yMWs4hpDcwpZcCyBjjwSZpelxQll\nQGIm\r\n=PAgq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE3unlQgLNRcaeJx1xA++eeyBqpdEfqKT1yQTyU+NDesAiEA2+c8OM1R+otkoq0vIXmM9BghOLI/7f9rEjHw5d5zbAA="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597239751.0_1597239760744_0.8073837775451345"},"_hasShrinkwrap":false},"1.3.1-canary.1597240853.0":{"name":"@joist/component","version":"1.3.1-canary.1597240853.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597240853.0+b841797"},"gitHead":"b8417970039bb1c5c36e274a1cff451320b1491e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n### Render however you want!\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597240853.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-F0HjGeMvOmAZNtvoyYetqOchFRxvRo2WphYtBfc4y5H9h+jb7Pkn/9iktCgA0exTi2V174oP7Coz4U19ByRI+A==","shasum":"e3625905b5929d3cc04d745f4f9ffecb53273b54","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597240853.0.tgz","fileCount":31,"unpackedSize":34977,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfM/YfCRA9TVsSAnZWagAAeCwP/2Pki0mFjq50O7rmqjY0\n2Uv8ypAxtOP5SISKkfVLR9r/cjapEOs2fTft3BrtIrM2o86+R/y3TPotg4+5\nz0ohJbv+rI4NkDs2ZjHZ0zSGMPD8nqF8AZKDr71lVeZ0XLiAmDrB17TnAyaj\nhj2LjiZaD9s30IynL+LIGjkQXiKkl7DQGRy/f4drFqIphURPEReEymDa3tVT\nirN8mZJkCnaxDuWTryr/ApJWus5Bop3RftzcvCXeGpTdv5FiHLPYPrIVY0DD\n9BdQjPaNf+vpTTGySDAfCfHR09++O9SdnzedA+p5WhASdyDcBNl/qYuMz4RU\nIz7dfQC34BfKXbIfbEqq5qC0aYKdWZYm8HGzioH8L7nVUebB51cMIHaky38G\nxzZUz4XcoK7R0WbptVxhrLd74klpdBF+N1LoJNd+sjsFDjmVvYJplKLrzupe\nJyZ4zddC3OOSfVq5CpONpSb71keeNo6s/pRFZSp97nb1E1jsUxXJQIDuDpm1\nFLdA2bqUz22imuYgkPiGKJKOcjf6hGICVo8vKVieKh/ffAjcB5aHvMj2PUdP\nwrukXJzSl3EWpc9ZTuOUEgCoWQf+n5Ju1iujVGABe74/q7CRjxYxf8wVyVeU\njDRN99HDg3qg/DrQuGIfm2ixXbN8dQZECPIjKrTGIKlIFri7O6LJT5XQrVfT\nzXV+\r\n=mmTm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIE05YVlAavNZL2Nt3OgkY6WgSMQIPCbITRLzYYdt/MBUAiAReRuzGLbTANTZhr12wwKLmvy9K9g3wu27PWRUZyIJ1A=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597240853.0_1597240863189_0.5724536883616536"},"_hasShrinkwrap":false},"1.3.1-canary.1597244062.0":{"name":"@joist/component","version":"1.3.1-canary.1597244062.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597244062.0+49c4ab0"},"gitHead":"49c4ab0cdb1ac5e6d627aaf65619166f5d439b82","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\n\n#### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Render however you want!\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597244062.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-WivpOtlrTheQMFTQk2+VUnMGtGI6abSJPBY/VfLNcVfP50SnY7EC1WqKCLyFAcM+TboS2nVcay6mcwV0d1krXA==","shasum":"9d712974223d0af6bee4b2b5f0d054039579f968","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597244062.0.tgz","fileCount":31,"unpackedSize":34979,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNAKnCRA9TVsSAnZWagAAKGkP/0dFWXxtiyWQ90vqGUBb\nRkiUnoWi7uFPpqu3I4wqozxEJ5Alsqr26WRlczaTVt1Ox2hhX7zyHdGW/+63\nmh0Hb6blo7WkzHpVtfCQB+PYyMLyo2u0qIHBraxG03Akpkn1x2wjgBZnmTKP\n43yY5C+vVEG6sNXoC+M9xAqhFuW8N3g20Dti+7mTKdranspm79AJNkCxY3K3\nDxMcYzcJHQFcE/uYcfQFNAn4Qa9jHKj5poKWnPBU4FIzRPENAO0dqb8nyJAJ\nMd+6kbYBp0SkO/8cANgJsVQ31LTI4Sl5xTrfOQqrnZiCMqsbNowZcNmrSYW2\nkreelRWndpIaWe1nZyHKxPNVivtQ2MV/Nm1CfVF947VtSbZ1sCztclLlcqpi\na7152BAfbyJ8WCCeYiRFleVU7T2OOOYJPLrxS9+KoXoOmKTIKbtjM/mo1i/q\naNOxnxXf9CG7u801/9HV2BpYOyFnqXx7YMSfaDpSbPa66/g9YO2C5TTSwXrD\nIWNg7mKZzH3zofri1r35cXkhBP6RWDzYUZlSAsEMhPacfhlBAqnbPgdFNFf6\n8lMiB1VD/n1/Ewsk9rsCCuFlXFVtCMc3z/60Irjc8dCXukGzM/4+u+CRsoIB\nVAj+m7a/iYRIc3naLzptjjOVpyDIxs8QILWeHghauTi+zIMjIN/aE4W0BVQU\n4WpA\r\n=TFyj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHipwC20BZWyY69Bq8AXRODnD3A9BYFIxHmHrqQEs79mAiEAq/A/zdWnnB0+ihT45Z5uqlqWT3tFjahs4jUTKZUJH8s="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597244062.0_1597244071229_0.6236009617615854"},"_hasShrinkwrap":false},"1.3.1-canary.1597246153.0":{"name":"@joist/component","version":"1.3.1-canary.1597246153.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597246153.0+989e46c"},"gitHead":"989e46c83cf191ba81c7ef9fbfe38bf977c99c59","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Render however you want!\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597246153.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-z39Orwvp66KsNM6mJVRuKxQFwXw8r7jqRVV4SGjaRJ55ufUqCoqsNTidPVjoiWF2QLD7GgKc+gif73c85FVWZQ==","shasum":"cd25df0c8ac79b1f95d8827b8e607ed47cfad6ed","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597246153.0.tgz","fileCount":31,"unpackedSize":35093,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNArTCRA9TVsSAnZWagAAdUQP/2N6CYlupNgTZzuhJrrM\nGWglSN2ZSelBytY5jxArn6VUX4SlRAUvjIoHek5U1ClMY6Akl71j9FEKW717\nL/qnB7JtJu8idVv2DRoTfzbBFoUnx9j5V859PAc5uJMx03jKq3byry71ITtj\nKEQmye2GBXFTaROO18THGtdkZTvLFwB7wJrZjfmbimxMM4bFZFlR5H+zORWr\n4u2+KnjjNypBYD3eZJsPcvO19k7EqIfd/mgQz+xZ3t5lf8rKQpx3PhuzSLIX\n5ycU+tpgTJMwg6yHhosy3mxjoQru5Zttn5IR4aXvjd8SjNJ1uwB4MZNhEGLm\ncMncu7sY2RGwCCCqgVdquAGarhJPhCQVLtlj9sjHlSuGiG1VHEEvZlsgBNx8\nwPHvdtW2stLxifqh489nYAwmSwxQvua2hbgflsrVPSCa8iWpdzK93sz7tZQo\n9rmAIpuvQlbpeP5BP2J409VC67N53cIf1S5HXPe49+BUAIZ+ULyP3LwULwpw\nI+zN60Qfm/HVsbwUErJ5StuBO/IxNDgWj57thO3wMScCw2RBH2CrV0E3GVf7\nK4GFKzheMhMAxUKvEXhpeFhsfApVLCKzQsBn3F6navIZKumTWTRKTFs/zbXl\nZHWggMDTKpR/AE5Dp1kvtax3EwSHOUvs0tVMD7Y72tXGAZitWep98mHfK3ko\nMhSO\r\n=LLFM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA9nO1ozRFtA0EY45h61KCAzrRw9u2r56TVrXa7GMRwSAiBNY9cMa4bJR2vIijPBoiXuNvY0TmN9Uh0IBpCLjrBVAg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597246153.0_1597246162482_0.13198372068039022"},"_hasShrinkwrap":false},"1.3.1-canary.1597246631.0":{"name":"@joist/component","version":"1.3.1-canary.1597246631.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597246631.0+1055a0c"},"gitHead":"1055a0c691ef3060e5e095025915a733dbb866ee","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Render however you want!\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597246631.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-vjZwdHQJtxPORPgUDMlFBT5DJ5ajmpEWd+yaDkirAZ1zMIHDxa0gKBjb/A7UKFrZUADebL7THq2b7BD6vHin8Q==","shasum":"d084dd04a55fba98c1c6f4290a052300531bd1d6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597246631.0.tgz","fileCount":31,"unpackedSize":35093,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNAywCRA9TVsSAnZWagAAVBcP/2sn4FIjeVWX7ct37iik\n9PnORnNPFveJ/GX/ssbOE6uf+RsV0v3eEExapcod4k3blE4qdHtWxIVEdDJX\ngjbVNfmLcZ+ZAKOeDDiuLlh7/ALVHB2I3ACCT2SeMvc7ANqLQU6zU/oQ1omG\nxltPtvSh1oaQIwP4XhQvS+rQUzcI9JsRgya/wqwRJH1Y4mSjmSb+qgWQHrlR\nL5eoTi+EZ7P6CWMHcRKYtdXfn3oOFD5h5WQqvm5UdCPbnpg4Qq/l1uqw8sYI\nR3DYYiYhWMbbisMstv3GEQZwQwbKkAbA1+YVTp/0CrRWLYrFIuOxyf7L+cIb\nKnZgxC10opoghRAvJnjCYttdGxigDmDDHjZ2lu/HxuAt2tuGq+oCj83VCFP9\nXm/ltQX/+y5ZYuavpEfElZCmtl0bmIyp6efRNJxLikNij3p0zHPHEN6R57AM\nbfUB9MJ9kIfxLfcuyigimd1Px80RnYtFE2cbpgpJxFLX17HTA7pALdO7Vby1\nz1NTkYYRxIUbz38MQl6ueqNY4ks9uANJ2PFWq08qMuXgLiwkt4y9uPQZGI1i\nBXnpQO1kALleddviOyPoHLXbrldE06mgSYj9+X4+1/Zx/oIyTkGV31/DKgpW\n1f7vdC3nDaPcC57lwCeYCHVN3IzVMi7IfJg2BgPQL8yPoZQWeI219fR59lXt\n1fat\r\n=J+qQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCX0fhUS9zdndWvMdrWqRjvvbEDaAEBEYmX7hAt0xibIAIgNbX7ZEMizd7gGiTNNNxLx9MyrzJ1XTw91NrOwJTMV/U="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597246631.0_1597246639997_0.12524663696286376"},"_hasShrinkwrap":false},"1.3.1-canary.1597262701.0":{"name":"@joist/component","version":"1.3.1-canary.1597262701.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597262701.0+d1206d2"},"gitHead":"d1206d2f3f8d7540c9e5f3da3230b144b1111298","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`<h1>${state.title}</h1>`\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597262701.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-f77792AtpmFmceI8jTMEh4lupvDZLfshobG4GX5CLoe3AEC21Q2mA5Q+68jNjkSOS2+FFx5yhW/l7NE4vUKuOQ==","shasum":"e40ce414153c794c1a31894b64bd838d02379073","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597262701.0.tgz","fileCount":31,"unpackedSize":35437,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNEt2CRA9TVsSAnZWagAARLwP/2oiBnXEkvThSvieKpuf\n1FeViU2ZM0ie9TS/xUJiUpFRh4NeBbXDRlB4sOLT5MRqPB1yxFEgxY774S7V\nNeHn/N16AHX9WzuKy4jCZsgpmfuta7NICsgeHr6Axs5IHuuDu3nsD+xljTBA\nJw8+UJvSU9Nn+3rT7YY6PWQ8fc+cIpOaLWizc9HUCxyPsY86OvheCjjal0Wa\nRoGeuPngCw19MbQ2SmWGG9QT3rqJJrMzGyFoHCZ5z3KRboe1XXW+btERsl+8\nlLhle1Y7xJYDrnnsrXO+86Z2KhZNfdG0M4I7VwIdGGCNba9wWpifQObIrAio\n0C+dO1RLF0+Zg8RnZTrMDVeMP35ZyknrVcHBPQPVtEvz+CSMzE8PJd3MFhim\nKJido2+GeP5KyhTZbe5oW8r611XnAaPe99gorjhKfpRV96kl0JMXwvWlWiKo\nqD62PFhR3I50pAFci4f4QWqc2nAe8FSGy72/mjchIVOCTEjpLGNZhVMKO3vg\nas691vs9Kpr7uh+dYOxt+yKypuNyu4ZvXcQI/mQ64gzH3tP8lRGnlRtM+O1O\nYYbuqZwsfbimcof/nHjbFHI8V8xAlQWX8llY32X+kvAkf3AaaTfRfMjCfXh1\nzzQD85bi0MounJR1sz/NFuq3E48YxLHJh9zQENnTeu47z+9kFWx613I8QYtS\nAfCb\r\n=ageH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICP3V0QMPJb4t0xBMyZhBmIlT1U1FgLhRP/7XEKlNawhAiANr+ewWFaJ8IsLeFWOKqF5taXAj1C9ovM23ZUsD77FxQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597262701.0_1597262709954_0.6593965816954366"},"_hasShrinkwrap":false},"1.3.1-canary.1597263673.0":{"name":"@joist/component","version":"1.3.1-canary.1597263673.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597263673.0+d85b1d1"},"gitHead":"d85b1d1cc2a39c448349f7ad08349229e33daa9b","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597263673.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-ZmP7MbfjOTMsKE3prCmVXG+Lax2Bf5FG6iFH3diUkvZcb7G5UEV0kEmHOieOVzxLm78MDu7tPxc3g2/4UFjL+Q==","shasum":"ae0b5c32fb93a0f30731e11867fe5e122d63824f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597263673.0.tgz","fileCount":31,"unpackedSize":35449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNE9DCRA9TVsSAnZWagAAJBgP/10T9Vkg5MmviNctwy4l\n9OkIl3XnpIhwcx40XRmXfDKE4fh7hdY1nNeBixQJHrP0lOeB+BWcEotaap5m\nE061/PBeHq4ZuIiIun1Jhne1T4Zj4Z2ZWMTeRH2vPiEeEUj4UVe4c/yNJAsY\nk6nwzGGM5ceTGhAVxQn0/G3KKEP3bdp7JzrJZhHkaheDDjp5eD8ZAog5CHZt\n5JePx2NqpbmPP65jngTlre7yYpbJ91PS1Afh3wuyn2BatxkhxESSP/H0gmHH\ntVrcS/C+rk6op9sj8gi+LsyIndbvIivf2wsdmxnDvqZyuJVJ14IDNQQ9Qo7I\nr42oef/Tx1CdMmixSPLYBNdkeV6xqQtJn4Q9tFw8MmQ2LvrbflDSImY4QpZf\nM1oDTsQIoF4oWHev9MD4F8ipOYKRLxCaY468qIMiHY49gKUc40MFAA7vjhDb\nawytwRi68Nw5R0WGT0ooeTeyBjKv/KXgg5LImbkU6Mjape7Ls4UNE8PsiYAU\nqyypHtxjTkDM8FWlfDLETWL0h1ePYQhYau3chQw8yXAj6i1ewaKfWgkzUgYA\nGGWaZPlTjYQuBYOiUnKJZj7Gf6t0WVZ0ApesUR8YOcqTy7T4PP4IziWWk/EE\nkffsxXikskb963rSUdowd+m+aFutvDEcjTNIBew3K3Ik9XN/CDe+OgwznRhL\nj2yr\r\n=pq/M\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCID8+pZIGxVL2jGuxO1E3T+gfSklgvF54hSzsO/npWk9NAiA6oAMM8MWe3kRP/wHpypzPACYpozUoQxedVr9UmmNrFw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597263673.0_1597263682402_0.4947092570066205"},"_hasShrinkwrap":false},"1.3.1-canary.1597290629.0":{"name":"@joist/component","version":"1.3.1-canary.1597290629.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597290629.0+fe23eae"},"gitHead":"fe23eaeb3a4793eaf93664e04de6ca09097b1718","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597290629.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-u6GZpr8uIc6esyNVdyq/sBekGGv+woFjabeZXASympzLrka6M1GwmmNo9fYXo0ZOljlIKSWPW2r9B1xddvrtVw==","shasum":"1426ea6bf389deccd198fb3c1fa219960c94af6f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597290629.0.tgz","fileCount":31,"unpackedSize":35449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNLiQCRA9TVsSAnZWagAAi3QP/2CFYZwzhvTMIYIbk/C1\nTrOLwnxTXhm+OsXAnbvwAX6q7jYKWCmo6/ITGf/Ys8dI3LdiiMKiEJyRkdOM\nMnAAx4S+oTodISVx2vOvnKyrp9D+arTxLwX/SmGH6SZno9/sNdlQ1aAmzZtP\nU6qkgpLBCE81DEf4kjx0kqLmhKP7rBC8Sg6MyZvL79iDSt7F1JZcl0fIn7wv\nxwJwE+ga0VTsj/mdVFuJHNHiG9b/+fNGaGxyKyLFHVdsuoxD+/wu5oVzBMps\nIQW6NEVpiZuoTbWdWF5nBRS0Tc3K37uZ0iJ3H63J8CwFcg79a9ieV2f+6Qvm\n3cNXRoca2zxREnTEA2n0b6d4h1HGp03T4r5/FttCrbJJMfm6sLuXsskhfIzR\nSkIxzFzbggYi8cr8GKT7qSqKKik189gR9ZfJh5ZA2AKo+cKxfU5piEC4GU1n\nxQ3zXCJDvy/ZnFpq4M72OcIuPo9YDrz+2sLsuXFyMCrzNAHbxWkM2pN7Qxct\ndNcpc6+MzVF0aJ/T9JY8/SaP393P4Eipp40H/Cd4e4K5rte97hNQpjcOLyBi\nO3aj/GCLrGHWYpB13Tk7KrZJ3+LRl5ksKMxYb17XPl8PAnyd/xTozae/ckUd\ngGv/PG9JeLP4x55epmZz5LxlhYz1jd8iW6GbYhBkd692dYaeiDIRPK/mikno\n/uIz\r\n=JqM3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC/i4eGCphjdk2uL4JP3Wfqe7lfB2PEyxEMV4iu5m/aBwIgIs/JLDNEiWDv1niFDbthFWnRa200m2kgD8xRBm4t+nI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597290629.0_1597290640213_0.08618812453761615"},"_hasShrinkwrap":false},"1.3.1-canary.1597290988.0":{"name":"@joist/component","version":"1.3.1-canary.1597290988.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597290988.0+dda8c13"},"gitHead":"dda8c13c8a72308e4733ad3647123f0b62b48ee1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597290988.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Ccc7SzBO/yM67vgH2pyr2xPBAJ6jh5jD++X08aB0/2AKI+Vh9K72CSw6pTC6xByTi1zZjfEseYlmUT9MMmpvwg==","shasum":"cee939ff9939bcef7e7aa2b771441a1249a30865","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597290988.0.tgz","fileCount":31,"unpackedSize":35449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNLn2CRA9TVsSAnZWagAA6UEP/A4oyiL4orEhVNU+YIGZ\nK5XqcFkBL9BoPsZ0tf/6CkXqnsHyn4QDQJSoQZguPlvIkgD7+zeNMij6aplo\nvbz7Gm7c0UU0VOOJf7wnclYUsPT/j6aRf4VQM7zv4j120iDvktf/9eUVSCkd\n2kHl94ox0sFZD4ZaYmSf/aHjC5ujQl4N8EqBRiBkR6cwe1Qs0XddXKARxB1r\n9aFskSbqAochdQnCUR7hshnthUKwMCDSpsHwZXoZxug9Gw1xoAZlkmCT/Xid\nSaBGL0CrP6SHnJnYEUXeUzLG5eACCFtdGVP9yDpnlzLMPeqTFlQCUPIOnK5i\ntqr3aL6NkY0944QPHL8DfCeMp2GSgnI+FoKWS/wsbzQlpB3jEDiBRI135/BJ\nmS6rUoW0u/cAio6D9NrV92g7NadbxgZe4nxmOW8iVOAN4v8xZ6R+sKCf1Fau\nuN2Ne9PLY02ULQkSG/SkMBM394tMzXkB5Phb/RNl76Fdta0rUuuKlpgzTZYY\nDZNXhrWgpPaMljJNUdDXe9d+fAFlFedWykGAmqJLMjhE5zq9QQo6DMKlLZsb\n/RKCXguVquPXwnxy7dtuXOAoKH1+s6HgxTtFfPRnVW9oeCPJnqv0MHINfaL6\nK8C9ieNesInIa1LF3Mduw1A4KavaxTSzW99UEPpMxFAu+1l1qKiulxPjD0Mw\nGMzs\r\n=C9ob\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDSYmQODuPLummqzBUaXkTBQIZTimJF5/4P+BHcQmBfbAIhANWPUBE1YhI1IHWp+sm6OFBdAcO+4e6QC0m1R0DL5MAN"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597290988.0_1597290998455_0.38190274826682424"},"_hasShrinkwrap":false},"1.3.1-canary.1597291029.0":{"name":"@joist/component","version":"1.3.1-canary.1597291029.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597291029.0+6250512"},"gitHead":"625051215d81ba6b542d93b6ca52565a9e0b137c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597291029.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-A9Xto/IeqjuXZyDdtXQWVgP94qjNC1P654Lz8gYVWC92k6qJCyRSGcUhBA3mmJlLzdjTP2EbR+TCJvclrAAmkA==","shasum":"29c5b9dbfe360f2d6cb2f1dd9f75ce9953c452b1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597291029.0.tgz","fileCount":31,"unpackedSize":35449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNLofCRA9TVsSAnZWagAAucUP/1teeVeioL0HvTyMvQFy\nCs+hvSMS/EnLnPi2KWweTHmYy9g10emKWvnhwkZJbSi9V9qjyxalURkzorsx\nVpk6qfg8VpxSn1O9axjtxM3Cs4nfTdwF7GypF6yyhFnCUuS4Mmrit3E/HzuE\n+D/kYyM2e2NO9QrHBch5OT5LsY5wd8QFUTTchFf+sT/oiAmMTLwpxmQRxq0g\nQvE6ndb2rdNpbF5NykbX5kUQizkqwodVERSAsYeW3rHL8FY75uNdNrV1ZyKw\nmMJLn4kTZnw/9A5Wzme3hyxoaJiSrdy2Bq/K/11CMltxvkMAXQ0EXPkTagKQ\nSkiuO+bS/ak2ANtPSxwMpsa+BHvd29eT+oLPBrMwI6pizxH0ABfOt401SIhw\nQWzjxtJj+u8X4A4Ozc9rlei7qbJFDU9IeRx28jlOFZwZ7vOmWICVGL+vg/dd\nY3oOz3AdPLMP30gxi4O6z4rV0CP9Msf/9pomXIF7QW0A9fw4a7pYH7MEwnKa\nKc06388omzlhN5tQAcs2trFOfRmgReTE6EsFXtTdGfjM3cvUO5OEMKyfoHLM\ndJBH4vDi4Xj+diQolM5ZTwS5g6v/st6irteX2q5YfvsUzOlLnadcJXqLnfPo\ny5zH+CSQ72mdnyPPaB4ySpL5nyLF5luHP8tYHDN/2ITHBKM39Zc7gZltFH5w\nyGzd\r\n=OvvD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCU6JUECmM4qOsqqXMBkF/hPM9BYdhx7oa4Frdo+9hPFwIhAP7WyoO3wYtBCyxdam+MtnycCJgeOsfBJPx05U6/YSRZ"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597291029.0_1597291038631_0.7691132667951384"},"_hasShrinkwrap":false},"1.3.1-canary.1597320809.0":{"name":"@joist/component","version":"1.3.1-canary.1597320809.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597320809.0+de59727"},"gitHead":"de5972705b66301545760adcdedb293c0d5edb85","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597320809.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-3n6reA7hal92Mznz2hCLvOgxkQ4i4fhV8MYJtMM/Nat0IteMIlxVcjDlWsw5zFRcfWM2BupuEFFLNP+qh42BqQ==","shasum":"0d9a37aa85884a734bb6248b2eba51b7f2b4e786","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597320809.0.tgz","fileCount":31,"unpackedSize":35449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNS50CRA9TVsSAnZWagAAmoAP/i01TN+uFHcputa3vVik\nbFORorIXsGg9XAzRtFKZ8nJGXrUZz3KgEkZJGXF/SCwiAU854o7fTKArrckU\nVemkcdilsPia5zhLmbiBf5Q+If2bQlfBnw3r08bHsafCPUGuEcVnHdsBwQHq\nJuLMuw9SFBit/Krp1t+s43NAL3YVEndL2fss5bL+ZYe41Td6ty5AzJ95ZxvG\nbL9zaoRS16SCYbgTbDs70g0H9b3ju5hRSBI7crv1zY/lF/tILI7lW8dDOH39\n8g7+cN1YHCR5/YvVCiCPTYtA/E5ePPtx97+kP8+D18yXLmJn1UCS9c1E871m\nAcO+kS49z3Ra3ejbkapUXkt42Sn1ZSzv271hNLf4vK3ZLDG16nrzVlnCGvEA\ntpLItPx0ybhF4aRiM+tp4a5ppyX2uQaGIVScTlnBTChFjbmFyi0docai6u3R\nirqTA+rZ8TBiiClVzPdpVnSeklhKS0LXYn/+os3kZN9zVft6Vy6RePfOSbTy\ntufU+ukfS5qSJjXi1BOQVUZGLfxcjgB90PelybhVwIugZtWu7gnQr1mT/0uf\nILDmMmr7FW9JfFhsn7ebnYJlbX+S8L1ZQDAeyPlTJs/L6mxghR+wt94qOwlG\nrv3TRpKloy+f3Ng+mk4uGrQxSe2G62ywNbstYGJSS+RqxkVY8cNizRY6CBeV\neIuh\r\n=bYjI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFzzniM68Ba9C8E08dq68n5BIUIXqSQi/ZlisSJ1mBMRAiB/TasZtkhC1RyNPA7pHePMuM61N9mGZ6xOrJvcWpQ9JQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597320809.0_1597320819923_0.7673201560484639"},"_hasShrinkwrap":false},"1.3.1-canary.1597328123.0":{"name":"@joist/component","version":"1.3.1-canary.1597328123.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597328123.0+927bc3c"},"gitHead":"927bc3ca0a2ed62d5485432c661dceb436a5384d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597328123.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-bq7fEp69cXGqBaXp0069MCSBOY09XCHHSF1rUHyc5TWaCc0HOZB8FfOeMaUYibMxo8psk6xEXcdLGrc6L55IxQ==","shasum":"d60e3f0b56e74b9f5bce1126ef012815132ee5bb","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597328123.0.tgz","fileCount":31,"unpackedSize":35449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNUsFCRA9TVsSAnZWagAAkL0P/38AdAb2i6k8qeoEXemP\n5TQpdshetc98G1GJh4WD7Mib4rzngolSxpd4lpz0mYRZLZqwjCSeLjMTvYF4\ndoVSqMuq2EMuOG1eWQdch5YLoz77BxhbCL0GbocUnk5s9X4KTbwLfzwTD9qV\nyom35QZsHWhcqycI9ydY4z3PYikW9izFD5KoUOQ52u2TVy/7I64BZZRPBP3M\nBItCsMGuHkKMDlcPVyYqs2nwLNM+HG6/uS7aRL8e78hYXc4yeKT4KbykNTgi\nyfQz68GdyopjiXbBjgdontYMgLuhbIwhSozINEXXx6lQ6bJlJPvC5vmLoTg2\nkphsqiZS9rYRsHjZTShBgQAEhiPmTz57nZQif3TluL0rX74kgtHiFrSJCySs\n9Nud2DWrgqNAWFTqaNvirYP6PdDxoWjjJiPWoiCjMbWRrv++8VPjNg7MCNm8\ni0HNLbTDX59aIOEBQJYh/5E1DkMEcE4FsA3k2cEdz0MctX6b1QNRslkIdHYX\nfSO20hTnwqy3TFPyFGFUlmaFkgczlJM6EUxJVLflDgwLDZY1hx0xS/d7SuaA\nmgI2U8nuBwa6nz9orCZdfMKyu3PxjRyEirzbBZZTlfIL+D3qWRyySyaBq6x5\nUmczbeqSrPeUA7R7k6JB6QCglw45GTldodzwoKKDvo4x0KLMPQsow24ooZnN\nsr2o\r\n=iZ6K\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEiiZTLhU4hbmz2cxmkXN302UE8e9OMCJKr4Qo34KB6dAiAaGs99PwU2D8PSx24W4xvS5RSkgx8m0LMKPVfRbMCg5Q=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597328123.0_1597328133163_0.6421249783237442"},"_hasShrinkwrap":false},"1.3.1-canary.1597328327.0":{"name":"@joist/component","version":"1.3.1-canary.1597328327.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597328327.0+e8b2d04"},"gitHead":"e8b2d04eb3cf573f4ec742bcca3da220ed1157ed","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597328327.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-SmRUSAkqqAZERs2nEbcyVLq2bE+7HIIujZxHr/+qhJ+Os0ui0+JtyPe2eVc0MpuiJO80fgJhAzeDMlcs6/5Iag==","shasum":"656754e4848b52952e859f065300443f56cdd42d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597328327.0.tgz","fileCount":31,"unpackedSize":35449,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNUvZCRA9TVsSAnZWagAAYP4P/03q5TecVYG+ficaxn1V\n4UV/6fpf6B5un4RZlidtcqICcgDwWmADQ0EC5DEUR/BqVdTZUL5LW4vtwMdP\nren9SIa4VI0/4vysA/eESwUflT689wqBaw1tWd6ENLsA02r8GcJm1abvZ8Zn\ngJbGri/jfzI90tJqaNyvmF+lZJTiI45TwG3mT0XZ9ev8toKKls3ufIJ+coH4\nbtFG8dkcL0BE4xYR8oZheXc4t194qGLzsI23MWhSoNesTYZ4caR1BhpEE5Ae\niFVGbOC/jH6CeA3K1ZhW6Kp2FqbC/NF+0iIQmloGSmm+I33v/yvA8aDWo0wA\nl+njtyEpKPsm8X0cplPVQ0qtzNOHVXPMp5jjMsGtBBhSBnAgTSuT7DtceGue\nNpcEqGFyFg4TGpxGKqe9dL/KDxk7/6HfR0mSqHpc+w0yPLwh0Cl2TMAYQoJY\nxfzCd9YnAFAXa0uk8BMYeuAaWV6I2bMVxfJj5ksIxr7m3eBhPHWDTpO50ZzH\nwU/KRb+TM3LtdC2UcBQJVvG2SvlVRbkqYwcvYmIeiQaoR9r9vbhIUHzXdv9S\ndas7CxlWyC1wfMtFv9zCPZZzD5kndNJe3nyw2SUj+snNu6D13E8u2JHFQ0qG\nmRzcqJonWMeFFDOjzIx25KgV92ORurpU4nHhY05LIBhoK7mfXw+gC0RO1qy9\nXBEZ\r\n=lFAl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICRV3fWIlM9pz/D9ycDZKfbIOQWYpGSZNWMetX3vTGCyAiB3t1JNt4SrpTkHDW/VwcF4A2We1KAYHxp4dG1m9+gYqg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597328327.0_1597328345188_0.28956644524687314"},"_hasShrinkwrap":false},"1.3.1-canary.1597333919.0":{"name":"@joist/component","version":"1.3.1-canary.1597333919.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597333919.0+e26e920"},"gitHead":"e26e9207a7649f6aaf33900abd89903f86423223","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597333919.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-xMZTh+YRBkcy5LX7W4/eWdHoxpbHOc8EqdlJwCCO+f1Z6CAqTBew7Jt+Jb2VIR/RQIJfkd7S7Dn2paL85IitKw==","shasum":"e3475379bdc85da6a0fe855be2027b4e8c6c9ede","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597333919.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNWGoCRA9TVsSAnZWagAAXWsQAKOWl/nM9Aobh3v7cl92\nn+6c6vS5nyeza2qPlRRahajSicJJY6DtuZk+DtDY0dzLuxLoHs+tjXlZziTP\ndY2AkRDGyCoP6IrWGPUXuzeAiV6ahgGOZs81ZUb1m/vQqRyjd4PfBSuCMu55\ntuolJ1rDx3bDR0jM6k/ps6s1EgktN7HrgWSaAkPeSueOaSAdXN27z/QyRfJA\ntpxovWeyNhzFTuVU6sHrhK9hV2jUoM/YaEQqS7k2c8lRxR5+b3olLYu/JgR2\nM3sQggI18SMpp/+P8iGN8dTTCJkJ2T3p/DfhA5b1iMcwarEJhGCTot1XLZjs\nNmopIFHbSTz5ZdlW9Z/7eRwNI20x7RMAbgror8SoBD+UzVgsVc8PeULkxDSS\nuMq0Qq3jWgvCisvaPO1ewwgQN1ZUuJGJZkjANV7yN/F1XSWW8vdsgWqmeBV3\nKMRwKgXWzCYtfb2xBv/8WdF9m5I48wSvRTUXERUSFlRXezZULzzKg5tO/sRB\nZZsl715dl5Nk2sqoSWyfLFEbuYp8g4oaU2ZPWhTNftng7KWaw24OmX4FYR2S\n+aI5WdAbyWnaOXxjpNgbGXOwlCDH7s0geaog+coSE+UXEiXKGDAQGDG4TbuR\nCxVyv0HIWj6I9zjfNKBcYYaRBKwIYpTvjBjThaGpz0gxp8Sg8Dgpjdw+SZpU\n8RRo\r\n=IxYs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCWmGhvDkwQxpu2lxJS2qV0sUDRCNZYm6VUn2glGX6uzgIgHTuOXD52hZ7Q2mLmCj7fj31Pri36kfUlzKchcpObVLY="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597333919.0_1597333928079_0.46274576482334906"},"_hasShrinkwrap":false},"1.3.1-canary.1597349545.0":{"name":"@joist/component","version":"1.3.1-canary.1597349545.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.1.2"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597349545.0+0b9b398"},"gitHead":"0b9b39894483ed36f59f4792e38caf6149e9ac1f","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597349545.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-b39Sb5dWhoNHMrtya72L+nFHvO99DEG2XEgR/yDKF1RNf+XuHhhmicV6L1UvpjLGos25Ov8xPUoU9KFOfcaDsQ==","shasum":"ed6e7b02830912c76a0ef255ed8386bbf52d1371","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597349545.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNZ60CRA9TVsSAnZWagAAf0wP/0kaUb74oINTCN9BU5t4\nY1E3x9eSDeuAK7AzdUjYQUOqsfOeRs9S1Ou6hghbm3LUP3yNiLexiBmtkvQ+\nqg2FG4oRn953tXvBhHVWa5uR4lYJKEnA+RiFk4QdO4m1K7Ec/5P+Gp5VRgPh\nN+PnV9NxCxQdLI9Yhp9yEn1hxQEwyvEjLkdrLd74novTQ/kHC82I4a8+nqLP\n5CjR8mtm3wPjYAM3/lTx8GZmcaijmP50yfonYoRxr+0X+v1UrrukPM69fXGk\nwu6m6jM2y9iLokK23y5drLESuip7YfsMi7O1kXSth39GzXr6AxZLfO5Ab1g1\nZPAt6gjN7B3pv+4M6UKV9z7JjVwoIJzi9Uoua+jEKEIfXb4NiWJECfiXeagT\n4Lr7aBcOzTxP1j3nPxQc2PbQgvY1EmCs+Mmu+zwhjG5w+o96bSMeFZAMUsS1\nTkMJs04lTVdG6QwxK9HdMvOPDnTl0INgcnKxs9iZl1H2B96pZtjD2EjC6mcF\nkdrOsMwWu3QfHMYaZOlR1A89u3+DnZEcGms7prEpK3VpkXew3vVKCT4042mT\nzgK9nE+vQ5KFf4Cgeq1hovfIPV8WgOpBbOf87NAj4qZNhym+z+Q/vMIjLJqe\nT6QceaY05iSmtiopdDfYM8tshShqZNMyy/NC0AwBBQw6c1oPi4OumudhX+R6\nNP9M\r\n=VAkx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCwGS4XaSivvWCN11WOAxuvNQG7cPbSwX0OCdeRgrGIqQIgS0BdC73IybBbQhO50bvf97JZU38kU8hh90dNd/SHl84="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597349545.0_1597349555774_0.7217265746841457"},"_hasShrinkwrap":false},"1.3.1-canary.1597374778.0":{"name":"@joist/component","version":"1.3.1-canary.1597374778.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597374778.0+d48ec20"},"gitHead":"d48ec200ee97123a9f2b4c44bf828eef49116a9b","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597374778.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-lAAwaV6KgkWiEbHuHXPROl3gQnvDra41C684MMcWBj0TE06nRbEe41MUJq526WhaYoi0C/9Ubm71FyDdWZAY8g==","shasum":"0f1f87ee828538e932b585a88573a5ee8e335c44","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597374778.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNgFECRA9TVsSAnZWagAAoOAQAJDLVF5b8Tzk1aW51raP\nmTsANYCxGj2abCiJrpQ9gnkjJLynW5vFsxW7XLFDtpl6nBtxSqDt2GSQxvzX\nL2OAlGst1Qfo0tNlYqa8Q7DGS+eKxYV2CaGVBiw3X5EHS3gbu2e7y5uAKdid\nnOjGA8NPp89zjx3IeImUlnZbMaE2eXGW+KUQIvbsGgy1j2Fv0OK654hkwf5d\nTe3ysVNSB0BrS8IjKfXOK09p2bClEdUxOuKxLkAmGD1+op3iPmvrFIirEUIv\nsLP6bzQaMUg6iNR65S6v5k5Ev3O7KOVbPFwY6xh1DpBqREJpvc+zAwsMxPUX\nO8q4Pj4+utQKa1XV2u1Oh5zdoBpOE8/zYnd68aNb5RuOMfiZ0fBroTQiIxWh\n8dIBBIKQ34hiUZedqC5hFKr/jNZjeHQ6EeZu51IXMMfrlDWf/Nhv7XiDFfAp\nk0nN/gznCgmRMexeX4q94d9wCe5c0YKTKSRa19xx04s3ksgzdMYtP8eq14RA\nI6UmRFLRBrrFK4BRAE2HKHJYWyjsEPF56EoTyTa7/rVRfxq/DkPAEluWVuBm\nLyG0WzJih56PxY8Q5pJT9xluCKeZ1alLl+rfUoZyy5wfP4LFhQ7x+hPUThIg\nE78fbLBrhpCZ0O9okFn8BNsEdMHKXWIJIuAM8jgeFPJwVRlEZ7ma3iiuigtD\nhJhc\r\n=YqQZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA+dpqcFO8qo7IZg+uiBnHjoFQPso1i8/ZAJUaBnZwvjAiEAyjg8H+GkS5d8Rq8urJ1yNRTZfLXCUoAT5aeTRBzjZmA="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597374778.0_1597374788192_0.11421531389075112"},"_hasShrinkwrap":false},"1.3.1-canary.1597408744.0":{"name":"@joist/component","version":"1.3.1-canary.1597408744.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597408744.0+4177577"},"gitHead":"41775771d57f3cfc26af8c59ae061d2701e1be93","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597408744.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-L6oz3WUJnW74d1ksG9lZ8WbX979jkqU+5erYwoREZ3ROsWv6sKclcZgJD7EpeZvQnopPJ282BdCVyqwK8TBmkg==","shasum":"ebe248db2b354eff04b23412ed3449f1d2e00d5c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597408744.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNoX7CRA9TVsSAnZWagAA7rgP/2KYA+9s191GdEXQGp5B\n9fV/QWq0OGGT4tqvpZ6qRe1CMG76W8X16et0JiXLfJSpawMqYQoZhGtTPlvM\n175zl4uWWdZRSuF3iGPIRWgIr6+8nMGo/jvHjFS/V9xG+re+mDvQgjfUYOL2\naAHf2KXKENq0N7ijVN6HgyxThi2AAncIkWSh4wC+IX9+PqfHqZPAK5ht/mp7\nEoVZCI4awLiZUmJHnufqJX+cFusq7HfjbsVM7iOW7x7vIzMOYQ7Zx6qMSZ6u\naFy0xn5OcTqZDb6ebJoz730rDFVCPYVuvidLgPsDpqG+HfnqR0oVgubabYxi\n2Rxv/OQBevwsYqNLiGn/mGU9X+3Icy2QzBOJd9LQ8Bj3muolFfEz9N4Z4mBY\njJs4EGb6TDX+5vwL/n7eSn427ExtNqZpGG6zmW27AEDkEBhNdJ8WFvUBlEe6\nt+FTO8WEj46l7ASNmO/2LpIY+2NbDVOp8eU5qM4DervHC22oiHlOOHOVNS52\nqiR7U5tlidxyQrk1+W3TpBy5OKH8BP2D1JbphWjw969uphw+CYVAn+ahNuj1\nEhwLgMfo/7Up0BwvQZgHQt+X0EDk75nhpKIFLBrc8r69QEomng+XPJtHlWC0\nv86fj/v2YUvgcRTgK6drs8272sprWLJ8a8re3FFtHgRfg6SCwAKvjVvCZLr6\nk2nT\r\n=/Szq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICnKSXdRJ5NoB6ztpQSk8VoGamrnlKIf0of+AkcR7Qp+AiB0jSS81y+NkwbRrNvwuAI3RSZUzGg7MXKwgd+z4Ts9/A=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597408744.0_1597408763125_0.9418398795481338"},"_hasShrinkwrap":false},"1.3.1-canary.1597413165.0":{"name":"@joist/component","version":"1.3.1-canary.1597413165.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597413165.0+fc88b27"},"gitHead":"fc88b272ca8da4be488184e3a49c143165b10616","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597413165.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-8Y++n0JcHBJtzGV8mpyxIijc9Pq+ZdMrXlNBlO7JZFsOJF1uqFjQeX+DUz7Hr5Aaz8fl/5f+ztFb3qAvP/x7Fw==","shasum":"247ea627c45e680af798801b290d01da09604e74","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597413165.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNpdCCRA9TVsSAnZWagAA9JoP+gIQEIx/e7X5FbZs6ES0\nEX4K4b+VWX6LzB1UsI6IjdwJhI5RMJu/YFKQbEpzYvRDynm9ePgBwPkFjDMh\nQKjqh45H5QVCQYBmCQ2GPSK3l3xe4QFlwGYWLJg5ZPQEi9WTDdYVZR8L6W4t\nzkfPcML0MJirGtp4aaxp1eaoV/rLPzNzb1Pvu9faZ1NUVQ4CoHyZWLx8nbX+\npuXGWxxLb2WMtnAGw60G0jMlT2e8CBCfV1ZNeuT82Lol9Ow+bBycZRKowQI+\nNrz97unmGJ5si0Me6YlEZbjBBhRtjujioFTLBdUrPihJKQYmzKDaWmMTC4iF\n4DnZntHh3PFqI4MCavcJ0c6OGf9TJ4ojrlggxSAya7VBqLPQB7TMWqNDHprB\nTYxXQIEYqAjU2heM6zLIbjBG32FD0SMhZPJpBqN0IWtOWXQs4j9qDKqoCyCu\ngFfgybYfkhSOhH30hYqe0g/cXVO8VCnacCG8rzXbrKcTi8qhBTsy4VOaVOZ1\n2QJUj0M4muk6w6Uhn1bOOmT+lhpm1PTcnOOFnm+DA6arn9MFAvshxZbWKHNQ\nC3j9aB6nIHqBIyMVsmhZxxNQ7VY60hcc8GRjk8sL9XuekW/h7TPuDY3tS0Bg\nLpE3JPxU4Q1GxcRa4n2qR5VcWmnpw9lNauKJjDdNdTo73vOVsotXkadYkqa2\n70aw\r\n=368X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDOrJEx8ffZ8O2BzK0UAM1+vsuHsq41YeOv2IS1Kv6M4gIge8eCi2yflST3LbV1+7Vy65EdYNqlXJzotihx2Zjdjls="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597413165.0_1597413185845_0.7088128502481315"},"_hasShrinkwrap":false},"1.3.1-canary.1597431329.0":{"name":"@joist/component","version":"1.3.1-canary.1597431329.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597431329.0+b3d193f"},"gitHead":"b3d193fe8b45b19bd01cdd6c4ed26f0a3df2736d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597431329.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-JtvfMH869bIkIH+G80BGFyfZA7QLqYKO4IPxMzz/QTyEabY5qrkNf3xmqcW+o+1I6tzuQO+iU53dyg5Rrj05Ew==","shasum":"e3b19e96648789882dc69d3a03f2be4df337bb94","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597431329.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfNt4sCRA9TVsSAnZWagAAUO8QAIOzq129H9Qw2gjzIabE\nVvhARM2QGtBF/VJRhT5wl4i4aQqNpNiazPDHHZj5Isq6zSevzRO3E7q6D5Ct\nC/hcJmJckhXTi3yleoitOx6rMroYUD0GPeKiWVL5VNdJfSYAEjThZKR1gS+c\nElyrf8jn8AtwHoBmaPCYNbCMFrJaPWY/WSh/oPY8PeYxStyNez9ZYS5otT2f\n0k6W2qojPRTnayfGVdHEeFyNTH2kq1ElrcffFaokQw6PYNa/UizBYhKQk6PS\nEuOq49MnJrCXpURqfuLMgH6dJgGIuOUHbwa/4eVaN0sw53RV16uPVnsaAXKQ\nNw8PZ9NUQucuUrijozHQyYKbiWQmkFDIsRiQBiRNnQaIzMoNNTfA1oNj13Pu\n5t5Ytko8kyX4P9adhILTO0LPlF7fTrbZd8BhF9+85GdNwwvz31TSFIks8xm4\nr9d8Qkqpzrclv6p9i8zupbo5IP2isicxV5HriaGyiPF5kgR+LHUNi/VjTtDT\nhnfYJuXyxOn3YxisxrMStrInTDBwHNIqPuhbflXYlrzdFL5SW1PaGCBSgWA1\nqRPk8Auw8EUcYOh/VNmcbMLuiITmw0hGtfCR3sJXNzOQ+M7UB+7k1QDFrKIA\n23TABQXZ3h3Ia/eFaLXWMPl5pRu0TxqlpH2tqmPNqBy5U1VoGMoH8pCIkizh\noWaO\r\n=4fMl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDNZsl58IE1dMjDT0DM3b958Y/w1maN8PH2kHTh6dOICAiEA+GH+5sHmme8RHzs5Bh8XktvRnt7nowChMrbmSRbWC6E="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597431329.0_1597431339836_0.7889738578951493"},"_hasShrinkwrap":false},"1.3.1-canary.1597500141.0":{"name":"@joist/component","version":"1.3.1-canary.1597500141.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597500141.0+1a30781"},"gitHead":"1a307810f478cfb32e80ab277471612810327ccf","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597500141.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-rKYQENtul6eCInN0SQcj6PvV4wsaNOPZfaaeVXHHxktfaz5HhQ7D1fd4CWPLDdfv1n83Vy4C/9PRNIYOuSlDpQ==","shasum":"66c405575d4ebb7bcec00d3d04d113ae0a483827","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597500141.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfN+r3CRA9TVsSAnZWagAAsF8P/jC9sTCfLYG4ff7R/08g\neBuoBOBbn+1rqdjdNESIjXp6EZgUECDQBlIIBnHnUOa2Fvex8Kgg9I3znxum\nqAYbWPp/H5t4i7zjJA/SPtdWSZ0U6LWeDwVMJbqydn24Ks6bQRYK1QD0yw+9\nxz7VDOrO6XmSSJsZ0UG1SrQOs0fNGl02NjNVf2nocghbYpY+ES7n3MtQXKfS\nQAHkZgL3vcPEYJ0Q12eUj2wzLvINu9gAwENhJgcZaPLJ/j1RsDfMQbxN2rxD\nke1zzumQ/mTR3JsKvRn5YTNjEy2wkieqs6X8ls8FgAH8QQL0EmwlXFp6S+tK\nkPrnO5lb6WZ/CCoq14wJ/pFni2laf23hnU9o9ByAOQ35Ij6qloqGksj1vKi4\n4NC9cMC/RBRhbyVJ1CjtukqZkO6R7yHjyESlFkmzs+JLtVMdrG4lPhB8ktGu\n7qgW89GGNPUKMCKo6sz9u7Y7B+TkVfN/nIg1rWzesLRvyYXoWk8WaRe84oar\nw4jhRXJutsF0wxvFXuf+Wph9TWeK/sb6f6KIvwxvUGaF+hvX1+aMu2CVt78d\nk6PWOa0AtJjUo1VXwvDHJo0e97iqTWojkMwary6XvxzmRghiiUyAi/Rf9cCz\nuxfs/507QTKlQfWK5T/NcEUDWUrOGujpJ5J/Nx+swOB+x5ehggYCMbFID8yB\ntmkz\r\n=Dwpk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC0XM+6nm13p1nNHK4MUfoHpuQL0qR2r75GzCkXuwdWlwIhAOKvi6yryFVGApKVsK0Rnnc2/9p6v7vsrubfWO4dk+Nc"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597500141.0_1597500151409_0.5267231279299507"},"_hasShrinkwrap":false},"1.3.1-canary.1597578829.0":{"name":"@joist/component","version":"1.3.1-canary.1597578829.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597578829.0+946c862"},"gitHead":"946c8622b92afe972c6090c4581882be3a7e2785","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597578829.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-g7vo1UD2Q6TQ2D/kVHlfzsoN2dASIDcKEY+MuXKRR2dVfYMlNERywqVkFRtWoVuNC5T4falrqR0iPPyCuzbiaQ==","shasum":"faf6a0a2805ba09eacefcc659ced84bfca714793","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597578829.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfOR5XCRA9TVsSAnZWagAAoAYP/0yAS7Y/FAe0sKJ9jnIl\n9AnkrxGD0Jf0v7SSvqKu/sdXoD54P4DSqhek0vJCdBCzMmbYpPU6eVf0P6fW\nMSoHIsaaUPuki3HHmnd/zc7YHGXK+P0ZfJAv+On6rAIT3pLmS490cAC0CLQA\nZLJFHmfhlnYtzKETOZX/xrhMNM5i8SV8w0E9A03IDi3soBSE9LJFvrOcxVIC\nXn+frGrKJ9sopBxHzWjt8LOWGV7WDZT8ylFZ2knlDJGiCwAYkTVo8NTEWF2V\nWH4ZeD9HNRXXbjUBNdxEm1Q4g1WF7CKV7uglKcNTQ0WCgNOf3VCVJRjVz8a+\nhgMx6wqs2I4qANsraOvPzY8Z7goxtA5Tr0R2cMnW3zec50FGCfkZQKPQwZWB\nDhYsUEdAYMSyzKl4SxNNFUCsflGaBNpdsgCqC/DfJy8iMDGkYJEx2sLIz+8w\njP1u1moge0h7Ufzo3p/Y11YUIiv9kEU+Ew8IiUJib6wlJ7JafvrBsfRkSPzC\nQFGfozXZJbOxZkrw8xJ4VY+r/tMp2AqEOseJ512hMJdi4YfLP6BgBnD1j1Rx\nGm8qXED4wwLQAqItyIipWWrvJ9Z6aU3uEDhYVA99T451amV6auoCT1QkhDB5\necyPdBLmGa9DiviAaemFi2SWlndHJ/kN1dZj3egiDHf/CEfbl598AfcBoMcA\nBj+T\r\n=gFtx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD/bPld6yNTdSTvjbXJyh0DSq/ejeKgZG1ChyHgkfcoDAIgZ9cRaCM1aWIX6ZPw1RE53nl3+LWp+RzcgMnnskmMyuc="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597578829.0_1597578838683_0.897510450482994"},"_hasShrinkwrap":false},"1.3.1-canary.1597578870.0":{"name":"@joist/component","version":"1.3.1-canary.1597578870.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597578870.0+b7cc7be"},"gitHead":"b7cc7beff6bb5737748a5d960b7f5c7ba5aa5917","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597578870.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-XZF9cIdzmwlOH/Tn7lASPr2uD5v3dk3TUjmcL0mzVaXBQv3dzvPuhZhI6w1KXR1jFw0tllprDA5rqXHfZtQOzw==","shasum":"78ea0cb16b4fbc1208fcb8c158ecc9ddfdb5744d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597578870.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfOR5/CRA9TVsSAnZWagAAsPAQAIKrccWvnsIE0K0n9TRQ\nJ/+RoPqx1Ke2avWhuiF95fet24X0ptILSnA3MmHpf50d47mg6VVR0b2VHDFG\nDfjkJ3RAq7CtmAmQduMjZreZNyQ4/DOgViQf4wvwrsq0C2Q0TrSrHYUTiLDV\nqtozzYNDbNzrvh/sQFJj6YTCyx9r7+ARmnjjgMlwKKkWDs6IqBbOhvzGLs58\nzrAB0hJK90xlBoXkp0FzzKVSBUYaUknwbZ+Lwj0L4XXAsijd7/0u4RdQq6HK\nLigxZPyu6FSVUzByDi1TvSWMoZL5RXDWOPY0ygSDBLQzVQrSSWDYsGpE+cgG\ndQqvC2KDWpkseSUujbtcWL3P+GoNCFCiv1vHfLcr1Y/5/6rwQ4R8U2tu7w98\n33TLJlw7EFw08v8wJoaRMaKBX5zSKB0OQv5d2gakPqK0bMSmIqt37GpUwofG\nHUKU2UJOT0POu0s2UKmECP4EGj6VV4GGAtBe1u4bHh2jJt96Qb/reJ0VCKnX\nWHk+UFQS+W4t60fW1+18z4S72F3yJjCXXDnw8pqEq09C/426o/ROmGyAOjKm\nSdOWt9nkZ/3TPj+dNpx/oPDa+f47Xe6YXqOa2RZQjtcXgvpOvKDDTpidYb4c\nhNN8PBKFk5UHKB4MC7ju36ns5Lx8ELopOzabXVHROEEr+j4dOULZwJ5EDsSG\ngK4j\r\n=UwKY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDz3Oy71FX5VjqPW70SEo1HCTu9RyEbKgkHDNgQO6niQAIhAJ5qmOOGhWj3QCvQ1h797/Ix6w1CrGCsLKrKZaf9Wwmx"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597578870.0_1597578879507_0.06372734916528677"},"_hasShrinkwrap":false},"1.3.1-canary.1597606352.0":{"name":"@joist/component","version":"1.3.1-canary.1597606352.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597606352.0+cab0fe7"},"gitHead":"cab0fe70d848a0e3d90f0bde6290fbe1b866c37d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597606352.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-5JQpwydG9a4iPAyUKVDnsMhRySRw41FkVcGulq1rf9ZnnZBIlLOXhY3O4mLaWSqZnGn1ztvQ0yJ1/p65tdjOmQ==","shasum":"871f165a6680188f9669cce5a618d59c0b936f2e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597606352.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfOYnZCRA9TVsSAnZWagAAEFIP/jmpSe99Zm5UYd6ZEqn8\nS3aK10NkCxig/KR8JnvTT4QCSzlG6GHNZYwsILCpe+Mw6Tn/TwSHb8VrPXXT\nqalvYhVXPXdrj3Z6XQ+WmTwL5HLtNGN/13CMX2UgpaA/GFpyDWYlF0efywD3\nxOs/i7AZk9tWOlUXKV2t3aL8bszRc4mCR+r2Hd/NZ2Kn/vdYl3NbOEeSM4WP\nnhLR8kYt0VtlJ8PGRYHloXKtSVP+jokhvEpkW6YDuyA46LpOOq1QuKnMIWgY\nF4RVzF/2PGQvKNbrgME36tgZcGTR5r84MJrcyNOUg8tW3yDi5wzyYvkBdKM0\nd57HmGXFaOhrvCxQArTaS4UgUSnRqMv91RisOzsR41/bnDunF+8/SS+fpr6t\nOTr0XNXmwJiArFi7nnURgNbBLvxPUabj9LMr9kgbT+PaKQzokZia6m/lm9ey\nO0ujrVsQQj+T4GQ3JGvh8liGi9qrHQH+bsBDdNL00xXO7y4FSIMif7HzCmiA\nlragMsNIyHKJ71+KrnoEaji0hYvvnFNlWou7IaEYbX8/boeLueE07l+zxO1X\n3cfDMEbhJG2QmYJFfTANH7FJf2WX6T8wLvQUbbPFUEXcNs0LLqc28+tPDGPK\nlOpnoo3CXSvwRsVyb/+A/ESbxlHG1q+NO6oYAqQIUQknX5bl56uWSmAH+Q1W\nCzhM\r\n=74Xo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEcNolPwwnS/w/um2k+0PbF5cbXdw2uKYcTKHmyGmZIEAiEAy3ZLK+uSghdIsgpxtZlC0rbhG5DxnrvzMZN+vZGT4BY="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597606352.0_1597606360630_0.0036546056604171984"},"_hasShrinkwrap":false},"1.3.1-canary.1597609080.0":{"name":"@joist/component","version":"1.3.1-canary.1597609080.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597609080.0+7dfe2a1"},"gitHead":"7dfe2a16fda33d2752c0d10812dda8178e773cf9","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597609080.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-FGNr1OjwniY4u+TGyLTsP/+0GEFr0EgppdI8vArCseGenULKXIdMn0Oddg4nNRn6vk9D8sOVZ5qTfCjsgZSp4w==","shasum":"872ed35c11fa8e4ca4a72a6a19eb84c70286e81c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597609080.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfOZSCCRA9TVsSAnZWagAA14wP/0hSLVwQ1cbA9m3qkt38\nniOG49bS94lEw3FX00t6V3LHOpfpZo8UoQ/32VEaOCDWAtq0WZEF39RUuj2N\nUuvc10bVT4Cd0pdHzU8KmW3iqDXPfIWqCOj4oY2Ew6bl8453nve1eDcnMJyg\n81AKOOz7rMi4J4P3XDXXJ+ZYOi1mlseSi0t9rZMf7Vo1DY5hXdJuBKSWdiq8\nv1uPXzwgC9D+RGU/M1SJed6lWTF1AOo7+EO6CHF4cp1PzAH/1jddWsimo2Sk\n5m7k83a8oRRiWwTmGZa3IuY7hMm/CzSpY03VR+gK7BmWc0DOW5AtTyXnHdUK\n9cIyuOIudQO4PyZFMSAqVqxstAkgESRIqINHdc7OtnoX/DbJROUIGjCGsohA\n1gjWRWHhEqaq5EBNk3t7LT41JAiNvzrlyXE8sDltACfGC+n1bN/w0F+4van3\na8j9TXeiO8V0UpdcL7x5RIfupLR4QLxzSavYZ1ChF4rJyh19rlUN8+sdvLxf\nTsBbWnBTenXUTfw96rijr3k1qB/9jYu2xnPs/ZMlahVyM8FyzomFh1O+rgt0\nCFuvNfOdVyICNZJBphzJQIEeSxmucSNGwuT9/hQ4y2/bbwdzb3JW/5Yji6mE\n6nl7Pc3pskGQWi08tXnXM1UHmj7XiAkVFeJoP74ODRs4XkAOPuDnJ0Hrgixa\nKzud\r\n=iCEd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCVP5397z/2OjHjVJOewVUaBqqJ861lbbhTBEWYZD1OWQIgTrcu92IiiAyc4rVuLi4mBhFqHaCjBWo48u6k+7GhARE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597609080.0_1597609090036_0.3695375425611167"},"_hasShrinkwrap":false},"1.3.1-canary.1597711149.0":{"name":"@joist/component","version":"1.3.1-canary.1597711149.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597711149.0+bbd6c9d"},"gitHead":"bbd6c9d94241a4b7d441f36c7d87eba9391cfd2c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597711149.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-kkYPy7JpxxDSv4EtQ6GbYC+9UaWxp8N5eCD2ZAXCxZYOKsuSTiWETgSOryQKP9x0ywQ8YoucOn29hnljfrw2Vw==","shasum":"30791f5353c83cfe3fc42c7ad27e6042ddbf4cb8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597711149.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfOyM3CRA9TVsSAnZWagAAux0P/0YIlBVkbuD+FNKJoES3\n3azn9OwImLJeJWLxrTvIQkfLlRGRQQiQWttem/fysv5VFTqeGuBTxhCq5+wx\ncEsfrRZUIHu5pPBl6KddLMMTfZwwWFuojA+JrrDNVu4E9lGyL6Lbo0PHhuF9\nge0zFAMhX5gtGSA+hx/v82Fhmt79JfldJbEoLV+39pUiIMIPDnSsmUcwxzkw\nnjEMjA25Q/rbzDxpAJTcIeKVTixL38+Y9/Py4RD8ET5Lb66irdQV9yRAJhPX\n/xdJQXAb8GXc0bG2RVE11/geR4OiWsp3up6R14a+qY8UYynpHTwXYlMetKHZ\nmDayusntAkFZUzdJx/01aStC94r9+x5+n3ZwMENdGt63FU53gGvKhjo8hvPM\nRSRdd1jSh4zwOu8Yc0QADqoyMeI+L7X8BA5Y8ncIrX0OMLPnYesE7+A6eEXj\ncauMFs9ZtBCJ4JsLZevVGrXIZM33bCOu5svCv6bmp8LRR+A4OlbJuAjAPfrd\nfJPmTTV0R0X6Gc7w7AeAbfTfDvH1ReMYd6hng1D5ILOGM+/u2byfFxFCFI5P\n3MmgX9kxfak4S/ffu2D1hoXiySiCYejRQIWV3pVB8B6fhJNBCD2UmslUMaD1\nVnaljIKvNAxEu2/LzlynAlMNIxUMJDbhqlZs1SSfmTtEU8WAr1JozjZ2yEGp\nEfVk\r\n=7vkv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGaJFy3weRRSIWr6MzdcKJvOuDG28NBz8McRHjCbILo6AiBqyiQBFn2jszJhkXWf1Px3wnF28QziNXFEheerOES9KA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597711149.0_1597711158989_0.7144801866355499"},"_hasShrinkwrap":false},"1.3.1-canary.1597838191.0":{"name":"@joist/component","version":"1.3.1-canary.1597838191.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597838191.0+60682b6"},"gitHead":"60682b68ccf6ae4a6c2065d382aa83b17abf01f5","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597838191.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-C/uzIXC0ERPX2IhjS1l/xEfzy2RzFd5WOnzPWPUk4EhyMl5ZUPjRdX0Qsmuoj9UWYF/TtXdZGLJLeZIsdQWvWA==","shasum":"03cb08cf7cae0a6b0c3968124017c5ce00202978","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597838191.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPRN4CRA9TVsSAnZWagAAybMQAKHZ8eYQOqnfyblqce5z\n3cNmwFVjWnRZnrYZvEE3jOLNf48cM1nil2TrJ/tSHafNJEOc6P9Vs/34fUcL\neAn6fmbQyYjJneABOYvMh2N9wYcaUbAWCqjKzpbzNohBU8IiLiOBIr10o4Fr\njEXMOmGVUlNJqYvqymScBS+WCVB0XtC1MbKRWsZnYNlaYmYF4YqS3Glegoa3\n+vVWfcD7hmpdKhQRyluLgsbxooYtOauELyB79P0Bt/PNXwPXGRMYABZcSmZj\nXfj/eXg9aDiRYLEd1h1TIg4ldSa3JsWyz1tteFnaoj21zAeAJ0fY+/dT7TRr\nWusZgbxsN024H14XieIFRDE8CaQJ4H9C4V/SoPHam7O1DSYt89xg47xvZsQo\njh+Kd3dE+dQQJa+72wKYasMWj7kYMnebNUBQ04kQnBAJ4h+OtHY7+pQvBi4D\n3Wl9DkH55DHC6MZN0de9c+Gqj6oUiwzzbYAdSGH7S6ls5x5nQ4DohGKMdeMQ\n0TCjKDDKNFc4uuiJL/PnnAs5co1PTrjv/CSQnWdbqf99lmihctxX2wn5JAFr\n4yvZmwLeoUjIaMSxFS5RY5bOC3uDQTlfOYIB13vqr+AHhDSbpqm758mXLwAj\n5hXG3jF1vKoeWWz2jsx1VaINMR03GsEuXx0qAnFkhvwzXhVAEuVKdvDMe8mu\nuXoy\r\n=YP1Y\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB9oAvHZldqgmSDg+5XYWcU6cxkuyhcjzJdLHPOfhrUAAiBQpyOxJbrNkOGlKwpKrMM/vbgcuVFdKbbf4rMlwBIO8A=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597838191.0_1597838199627_0.09409115498864695"},"_hasShrinkwrap":false},"1.3.1-canary.1597840643.0":{"name":"@joist/component","version":"1.3.1-canary.1597840643.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597840643.0+e519148"},"gitHead":"e51914843eb66c229e9e261568fd05109fdfac65","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597840643.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-4OcOR3bsGuDUtZXIOZ4cvMTPnOiHNQjQifcKzVgErjiUCvXm3LQseO84835A8JFwZdUwlKgWI4cMOW61dJiMdA==","shasum":"fc27b863a5c4b39c744ba54cba3a724bdf64339e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597840643.0.tgz","fileCount":31,"unpackedSize":35375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPR0NCRA9TVsSAnZWagAAlhYP/jGcrLHKirbyKq9LRPhC\n1lD4FisaoHVZpbkczP7CCuLU6wDBeLbWL+mdhkKSECtM7weLyV2+mXd53Vxg\nCLh/M1d5VaGczsAQDeahUNlgas0tvPkaRzAFkQQ478Hb7F1nOHjG/4T/DOYo\nQd0sni27Pp0CL+2liuYGpWzhyX0JOEzIz7P0OrYQ4NrH2300GXo+XZ+p1eWP\nOZtTebCCYf3GJ3oa/zSABBxiiIBCSEQXk4rRq6mcS4kT8vVRIdRRXIGv+f7i\n9XRQ2kZAujogkPcxP/AF9u7puRK0CF+E1/R1wByPD4uf/z1Kp32AdjILeGOR\nNPV/M0BihdT++//v92BpPqo8nSOfkMgWCbbVgeSXsjtUsZ0Whg0BQ3G8ZuwA\nfCKkDZCvOsMvQNr9gt3uW1x/likKr9uGkPWXTpXGO4MNxPSugqvXaOCcp9Re\nHSL7W6q7TeXo7atCuZsf4LM80wnDqtxC00ANKPO5c3Q6YhWktvJLDcjuOgnp\nMn1neGEw3Xaz3/tk6NJJ/mqTEbuBCCuR3qAQoxEGppPxWglF+v/IaYtMaoDT\nhwOg3JYF2QiRIlxLqTzpsO0kpVG90qdYB1TEe6iTL/miT0jEZ/76FKrsUAMG\nunYPxuXMEpO349eJ1TYSuOc1TfFECBmKKdQeGoRDQW388+n486ayA6pqPHpc\nzlcZ\r\n=sQpx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAuc0hZlQ5ItBg3vpxZkg6qpQnR41F6+L98v6whLD0bSAiEAjNk7VS88Aauo/oftDyHumYw286GXOVn6/Cqk8gxfJnQ="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597840643.0_1597840653214_0.20435519933816315"},"_hasShrinkwrap":false},"1.3.1-canary.1597880798.0":{"name":"@joist/component","version":"1.3.1-canary.1597880798.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597880798.0+056afa0"},"gitHead":"056afa088e48d194fc417ebbf55c03e0ff18d7fc","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597880798.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-d2L2tJo7vtJOK9spjE6SP6X0B8c6QC1+mS9d1MkpBJ8M+kLz/rTiN6hvfuX9JxwEZHLTx6VgmIwdxSBJYc/HCQ==","shasum":"a8c5ebd124a28cce5e5881ef1d8cf73d903e95d6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597880798.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPbnnCRA9TVsSAnZWagAACnwQAJhpN7cwNKXpmgRnGLU+\ngxAZ7dkG2JDsYMfH4uVLBl4DJNGiK6m3wYDZHAU4fvl3BSm0+ZKPhSr6uj1Z\nbWinv9XsAgUq9qAzCh4dQZANP/I+1KDGBMKLg3ZHsys3Qi4S3w1Zeh+lsQFV\nRE8zu3JZ8A59MWicl8cUGWUOeQZ4IRIf0ktzT8cWFw78miVnkFMqr3TUD8sZ\nT4qwIKOTmewn39oEKuMQLGaiG+NPIvGxGjYE6+8AXqbCf2uTQRTTH20ChDKa\nOzet21kTZEjkvaKbUaz/YuGP8rKIeLktG/OQeRVhb/GAnmARw7WK+JBwyB+4\nXGHoioTu4945zBJ1muxNXR0Gx+tndBQBW9x+UWaEhjkkAwRLyF9uSKso1Sg5\n3hqLAIa3qcS4pGgAWzLpnKXI3ImVBbbvVmQ7Ukas2Ii/iHAxpIJCQ620ME3W\namKk7knQ00Z1CfuD3IR9hx6y7kfbKJEQkGIfKJTdddHkosF1GbQ6iLgGtmK+\n7+1JGRw1RbRFdBPYkA2ME5uazxuhVhoBdnr7dYttM7Vy5Nj11pSMRnjbELjQ\nlhs873e5Nv6QPokPBjO3E1d+m9ObTfnjuP90fKWchwEcYXZB+816EaHf+dnz\nxsDCt+POc9CSPBrbWHofbQgjzZ/AG9/hlNyWZ5H42aqcKfqWMdpqjkA299Sr\n7jH9\r\n=Tx9x\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCahkiRefzpei4uLSKXM+vet3GWbK3qv3N/qf6plIy6GwIhAIWYMS9U79pDKffZuWHeYRzl21QQtCjVlaWO8KvoD9XH"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597880798.0_1597880806882_0.560510228600652"},"_hasShrinkwrap":false},"1.3.1-canary.1597881741.0":{"name":"@joist/component","version":"1.3.1-canary.1597881741.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597881741.0+8cf4900"},"gitHead":"8cf4900ce50d31dd7186f8a6b880ba84c508384c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597881741.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-5Z5sjfYgojxdVDHvZmCSyGE7fT8vNRR/Y/xzW7HB3uQALE9FyIBHUZ805asK4jJS9QbL2Dd3dcSv+8cOMoKnEA==","shasum":"9da4c525373f7462c385b4af6064b631af2abb24","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597881741.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPb2WCRA9TVsSAnZWagAAn7IP/RDvtEgbh9VX96vmdZJ0\n67YJN5AYAYnprbvUBGMPBoQ4EIlBOzGxj9tBsGbzWBasolFEQ/RXnz0XAAA+\nilwI/FZ1UQp7ZXT8sfXqp002OpzigvWeAjkGmultUUbsnnJbb0b7a9xzBToN\nCB9AhHvhAVDAoFS/nQnlFndjsR6+QG17WQsatsXPw47yD3r10aiTPeAuTrXH\nz+CMpripYiM9RMwkx+cZWNSLFFaX+cO8goywPm43rUkFAGiJKNYfD78e6GgV\n15l6CBUovj/VjlU6ekF64t/D4a8LDt4utaBCluiVG7M4BGyIJtbhTD8oXxdl\ngEvoHhn6S5nbqd4aEITMCfL/Ipsa2jnJ01UUWZjN0g/rpgtFpizr0nYRqnA9\nyZzqs0V4mBDD85gUanDK/6nItg04wIAYvOVLfFHQRosrVeUKm6ujKZyiBXvO\nEwBds4kTkYQ0bS/Cimn5dHgyx2erkGXTYsPgT4RcGB3QKRxqNeo7mTfJ/l7n\nT6udViUSiDtngk7NEoaTco/SY84eXDJiHWX7DaXHwHsFI1+LVAb1XqUAmOZE\nCXEDxOrWNB9FJ38JL1mN3ynIO8KV656/ASvwJP54R5yyH3vadeoDNZARJhL4\nT+TxvJBDB8e2RwC9zHOaYe5QjSL64E/rGr31eczlhlE48AHpC9hXHljlph6p\nzMom\r\n=eUO9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGV6j5oHmLuFeZGja9g7KCSVU+7ngLZ2FBWkLiVECaWiAiA9hkl6h07PxQrfubkB2wdhxScRAHf5hVsdQ6yCPiIhUg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597881741.0_1597881749512_0.0694373684956231"},"_hasShrinkwrap":false},"1.3.1-canary.1597881860.0":{"name":"@joist/component","version":"1.3.1-canary.1597881860.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597881860.0+f080e39"},"gitHead":"f080e397095a6c370b9de3253d84e2ef7bf71616","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597881860.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-T48qPOUbbapLg61ruqcI5GbjERZAqbho12xKgbci0ik7mMe4uPbrIYArEAXYcLryMGYJiMZGXN7jEjkaS+Gu4A==","shasum":"afc26fe863b32f0919840869ef62dfcc0def5b46","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597881860.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPb4OCRA9TVsSAnZWagAAqp8P/j6Q4NlpLLgBubKyd2KY\nEYC3jdBzM6qSC3sFU0GH+9oH9PucIla1MO+S56O920v/fgTvfbXdudpt+j8t\njEXCZg5k9EM1b+bAlK395rV9IXK43a3LlNcBuskDSUFHJeepIMPfCGeFmmon\ntSDC1dTmS2gcmC9fZR3gaLTIX2xU6O7agyv8k9ALTRqVNrCjYEXRytqNnDsn\nyFkfQVbUbS+N174ZsWwlBmtTZ48gU9OfQH+b9F+hlu3N0Fo4S7G3lrrGDMkZ\ngra45ilQgU77ga5nMC9e50kYHeAgXh7BcmUYW1dL2qxat78cOchzoRny1Q7N\n1iB4eLzATP5pv2dBfoVPod3relYDVhnUn2K9ddB3Rpq+lWgVn6/IyMQzMtGk\nabHGsYp67xJ8f/S/0G0pgcl6/3bT5IHAwGFCHg3Sp6tQZoWltlzmae1508Cy\ntvRtETTiQ/+I5ahWuZ1msWjAxhZTgnQZS8ssQ5iLoeLBcZevFmws/+oybNzu\nA7/jlOexdyJrGF0jiOPUCPGxJpWXAGWxgl3MCp4hJJjDCnT3qtvdUpdpZQzT\nVoPlKoKK4H9FJ9xviVdo3AEFRrqJtV+oZWNO9pMVBUU7xUFOTkNdjg6UHPX8\n1TJmnMEZ7EA0vyMEKWddtqA15hVZKIOY5NOxuPeN33IGWIs/o4NQl6WIQTdQ\nbPtV\r\n=rfOY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBlQLNsz8821jRf482utPEChR7jz45JJW7z+bdEsfJU7AiEA3YiCGo5TqLMTPN8I6niLcJmtlnbso4LrWHjgKMCDVfE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597881860.0_1597881870173_0.6740737574101456"},"_hasShrinkwrap":false},"1.3.1-canary.1597881958.0":{"name":"@joist/component","version":"1.3.1-canary.1597881958.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597881958.0+fdd070e"},"gitHead":"fdd070ebe7ab1c7c906e5b5cee674d747c909764","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597881958.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-qMOxNK1ivWUa/lQqjDmG+5YSuegk7PGYiVnWbrPKCTpQGry+erZyTz6p7RS+QH+YJlEo5Uekvtrrw+WhF1ci7g==","shasum":"e91b71af948218128e1776f16e5a1ea626e4be0b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597881958.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPb5wCRA9TVsSAnZWagAA+MMP/A4ersdnF02Uw1uJBTtC\nJAH3UwXHCKrAL4tuXPE4qWfNUIBDchbAFVkbJCjTNl+pa8osJ1frW0h4mi4P\nb5mg/eT4Kb3+c28EY/FHQNn7c0Q2fjgXsW+r08dubmwTM0bDJhnG7GBaIUNa\nS3WMHwzW+S89Onjhv1eVjDWHYbVVOid2Varp0pFMtrmdpihmqZBlSxekvuZh\njacpklzXGAt6gixUeKBiLXlL9XKRDbbLWZm9Pb8rDIfQ9g8UUGr1zbiaSMnT\n/9E8avVQobaVuyCJmK1Udpr/amYMlkaimTHlTtdzKH8KeBUlfw1FEeucuPjj\nBIrkC3IuQU2KEPkKKWpin4V9eeLlePP1hHiblj0zgLGjg9geBJ+eo7tDfOvA\n5ZhtX3yhHPdJBl6d/Fl+7QDh8Z+S6e+5/r2wrPhOoAWiSDxSHgYREDuo7req\nWOJ1fpwjfFIXALxH/0NkN17lQBdgYB8TnUHFIOmSkCzoMMLS4u6g4TCJRwN8\nLAb0Y/+ojKhC8+nf6GURQOz1tuoD7wOK+Pt8jRqp7FOax8TW2fVkGdrR2zYm\nX8rmjGSsWM8q5wXYk3L0YOvf5UddgLWwusAgC/J+SB/L6Yx76ebAjy2xGmsp\nKKYyAXbgLTYDO3lNHeuLM5uhsa5G7vmZCe7pEO3ogJIcak3MuRddfTbbokjN\nC2pn\r\n=duh6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDdcFK0vnh32F9wXWpCCTZ6+0IbCVTzLtzBjkmN9zURbAiBSHB52FowHzL/eK3WK+3jzRXtehpT+cWk75w7SycCCvw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597881958.0_1597881968395_0.6520583993848377"},"_hasShrinkwrap":false},"1.3.1-canary.1597882151.0":{"name":"@joist/component","version":"1.3.1-canary.1597882151.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.3.1-canary.1597882151.0+67f6b58"},"gitHead":"67f6b5886bd1f7c16c5418c4bbc7965bc4813eb6","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.3.1-canary.1597882151.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-FUi+UpfJQtham6q2p3PJcoRBC3SWEKE8rXa0eicznCKshVyRShzrf2pWh4CmNXF/UwEnlGj6CFd0p+ivDIJDtg==","shasum":"479a463b4daa818fc568eadd1c6d9720563fa447","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.3.1-canary.1597882151.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPb8wCRA9TVsSAnZWagAACfMP/2Pk3NJb2D46foOAJB5T\n8E5rrz8qSoqfAFqcBG/lW6KGSBT1iv4GM2pE+8OOqELTDzOdaPhQWv+5zbu/\nOWl6C3OJfkYDmDBqA3RVJ/9o4Ge0A8hQgho2e13F8Tw26J14aQr1hbrDLFqC\nAlH1tp4P45O1DOBIGbUZKegLCxG50G0Yudbby/UtDiUhMWLXwnim3bPc3Io1\nxotQE0d+mum4Uz6Kn8VFbiQGsfLELXaShH9QtWVvxOd58TXBdQqiwHV+gL0X\nR9/goEY2J64Ww0Mwpooa0K32rLnpKKVyYhxZSyUKguHwaIEW8GON+QRrwmOm\nexcof6jCq7nOQkBELt3i4i7tEPqGotqq0/eKVwHxLuAtwXVDXyZvMUYjmSzr\nfLg1vNa9iP8k9FQVbtmroWYdldo0C8kict0uEJhKfWaQ3Z+7+z1UIfoiS7yW\niGS4n4pzXb9U+ee8nNfBlvCH2PZyf4sewG9cAOh41vdEsnyuTqXI30LX6+Pp\nMD6CEcV9GKgcQHGaLzIxQD3IwhD4wIbd4nF6MLbyqFCEN/nkkO3xehyISevr\nr80/PrqGILB5pGlQ0s/UQePGsHXo/JklUaVnOoQdUeRfLn9FGkzYsMAMmQ3L\nOQgt3bxzApq4o7o/738EwL7/y7O9zBQfbwoR7epPOkI/vho2NZHZyz2wxrWw\nV2EY\r\n=dfAO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA9ARPMNjmjlfo6+orzNpk2VphCJeAvlYXM17anEZ/RVAiASMYZj/HKtLWyO6xM4UiF1WMftMd27vO1j8UfxuTaQKQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.3.1-canary.1597882151.0_1597882159635_0.2727670344064008"},"_hasShrinkwrap":false},"1.4.0":{"name":"@joist/component","version":"1.4.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.0"},"gitHead":"86ad6d52819001298e5c3655981ebd31749a6c1a","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.0","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-l3P1QrB9MUr05rNyHlO/ItO7eArta2PIdNS6AFNfPvxeYiiOuEkdtr4+kE55sGjnQ/tgVi2fFUEl1i64Ph5a5w==","shasum":"c9bc31a2a5ac7289ca38686983a65dc999547264","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.0.tgz","fileCount":31,"unpackedSize":36131,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPb/BCRA9TVsSAnZWagAAWpYP/3RpUVaYd0fFej45o3b0\nNrPHS/k6vYomoQMTx0qT/RN7AfN3+uCi8bLj9iVemaPY/j1Y6pAWyENT39tt\nqCnNNyoqxXVBXIS2JUKw4uksyuJVYNtL67MvTSSm0FDQ4t1z1oA591ZVJQPI\n6D9Si7QXuR08vL5TouCxEoj2tc8oB5tvotp9dU1xKR+8yzLyexO0hTIkuKBe\nL+WlU2IK8X4R96ln2oswoSH/+LhbIhx2Yh2ZvkW2DpjeoSHtFOumr8ASrq9J\nhewkPdfaXSGlnThliEjpYCVP0jEtJ3w745+wshuho5XI9nEVE6Wg1IPgwH3v\nap3Q1LgfotQs/UC3MUeMXR62qGCrr7Rjlc928zekcarxz9LCLvl4ZgP1mClB\n1m3L2D3ocPWLdhRb5rurzjtc00pUQWN3RJQ1/zuAdTNOLbomLllqqFG5IeLz\nedYMPD6pJpqW3LHQvM/JgQ4Je8YIIQdzXnKGAfeEDvkJf39bqgim5EzWjbej\nh9qdyjaJFHlWvsgf8jVhzfMIkg7VYK5puwsJgDsG2RXx6hl5IcH9I6ioc4/M\nQm/FRd8f/4Ok0FAD+H+6QLsqbxkdSm8OT6XDgaYsqUFrVXZL+8mZBve1a+RX\ndBscpbMYNeWMikPub1kxrtX/hxeCdtGOV1Lvg8dvZF5o+bvlUqqyT7r7qhJA\neEGs\r\n=8fA2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICxRo0r8morCjoeAvwgA/HXwnnpwR4aCvh7wmp72LneJAiEArjA/iGCc416W7eoJhnchlULxQFbgw+Vx0UjVRtk3ZIs="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.0_1597882305185_0.18066296266265547"},"_hasShrinkwrap":false},"1.4.1-canary.1597882339.0":{"name":"@joist/component","version":"1.4.1-canary.1597882339.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597882339.0+86ad6d5"},"gitHead":"86ad6d52819001298e5c3655981ebd31749a6c1a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597882339.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-ApZj/KkOUHesRdGfbgSv5c7oufry1MlGieE1fgzyNUtAqaM7RpDAmoQ2GixYp6hsQp+EYWlieW12b6tXLvCU4w==","shasum":"4531f17c4a08f97785a87d1745df5afb07bd645f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597882339.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPb/tCRA9TVsSAnZWagAA2fMP/2yH41OrDgjq7DLmwyou\nQEHLYHIUwJzRSYYUmWeJfE82mUn4APALh+hb5DdQDq0hFIdaBXBQxYlLOoqk\ntYrVm/GmsYQ9YvMdF1DFuyAF5pT24d2htuE1Ju8988XM67fUruFp+TIIpcjH\nbZOBEe6Cknj+Hqd359ovaApaNYK8EUk9koIzHi5GGwdx3XRn4BNUAIvKIO0s\n61LSBAN0KlQwgmwjFMS/UaALn5A0ykDNzg1aRhEH03d9wxdZl82n3c+LbPIu\n37+nQPlhBOCSlZFhpidvjHXbDDPrZ98N9gQScoysvsYBQxMRNcgb3jFE1CGc\nkoB4CW+dBkhkHwo1Kxa1j/K6U3vnN0WPazjlW11EtodCwx0VBEbjbUghFwPZ\ndE63ofNIy8TaJWSqp0Zkm8z1yasDG1BVAu38fA5dQinArtTP29pSx/Nw8SYl\nYCfFhLlYGErb+XKWDQOTZ1MmW29w6pUhFj2Ssgl20MNgKrk0inNRojMONC/T\n7utfVFWxaHLIRLjJA4h5ikSItQ+4EIBdwa3QXXtEc3kfjS0IaXynsGXNypmH\num2NemumTqF+76GfbNC3Gi/BT9BSPVldqaKu1dhHBsBIahBxB4Wr/3oKzbce\nRWzK+srZ5WjwbMIdcZdhnYNyN8J/R14leufMVSIRM5Hk5m+tVG0ae1inhJVv\nIlsr\r\n=oLNb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC82nGHw1JAOi548aWVBkq/BXxlFivzmv6wwX4v5Oz2bAiEAwZJjRoeQuBvkhQJzSFKS2pEbvAjP29/C0oym4NKQDG0="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597882339.0_1597882349492_0.9078719741961228"},"_hasShrinkwrap":false},"1.4.1-canary.1597882712.0":{"name":"@joist/component","version":"1.4.1-canary.1597882712.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597882712.0+1318504"},"gitHead":"1318504d8f60c36833b32b6f7bd32c92db9155b9","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597882712.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-EeWHylipWfRDPSIDt5y+PwrY5LkxZsJf875p375jgwNJAo3jdqN2zFQeOvCBdELEFTnNle2yktMP19vGinPgEg==","shasum":"f38d7a1b35ac0722aac6329b1bd2b607a77ddc4e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597882712.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPcFiCRA9TVsSAnZWagAAIFUP/R1KvN6JrrQjIvqisnSM\n9BZewxpOoTyWe/CBWGzR3zZ666Tz4ZOgRx4ZEZCVHH9PiTPiA5ifQ7Rqabk8\nvwEPQU/aJSk3DjYApNQeky+6r11nzLoPdv5FP+zvNmHbUEebbAGWHb/CbRRF\n0oOZkOVy7ry74/zg1GbLwU/3B71caOFw0X+j+raJ7IxUikX3wtXOmeolGKRB\nbr7c3MIbNh5M8BX4Ngk9bhyJuPa4bnwGahaiHDYEzGxbWf08EmMQKY2vTYCm\nPJ5b8OS306/3R6TpPmBbTXRjw335RcYH+6va/7Jjztz1CVdq84jvHgZD/EIW\n8GXrRU3oPaqJMKeKHRksf6/jdHf8bDUtnurnK4nnfKO6Ps+Tr94HkI1iERxc\nkcXfuWyXYunhx5pUWMfnmmOw4uAC2N6efUr81tPRYgUm6DuAIwM1rUAT9owC\n/AZZoS0sy3qr5OiEqm1FxnuFztO3HlzAlpScK6s8CfL8tkS0xZvIuJKfIDvB\nGErmKtAnDhD9Zfdq0m6u+U2ENXoZmWjt6FpudtXINGbEHlpTi7wnPRkj3qyS\nCOWaJQDplZ/6MT93sxiF8T/LaMZLyFdbRwtuL/592wvbjbj0KbnbAYPOWs5X\nSNXTvo6qDxiF2KvhGTqSfTstl6vgRyEmyJBx2SixurgG6PsxJ3tZ5DsaTVvC\n7GSR\r\n=y9yf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFlb0sdzuXfkVTlRUhDpgjKAF14Kaklq6qGKeipS3xR6AiBmNlwQMv4d2wpVqSA+i6jKacLPMYyk7JtqH8siBYcYXA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597882712.0_1597882721901_0.9876851834972216"},"_hasShrinkwrap":false},"1.4.1-canary.1597882871.0":{"name":"@joist/component","version":"1.4.1-canary.1597882871.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597882871.0+d8011fe"},"gitHead":"d8011fea51bad214cf655d5cf991e175df5008a0","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597882871.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-aYGIV883mFRSPGohDUNm3O92w5HqsIq0bm2TCoOg7qGy7Y0ch1SocCzVM7Cnd2YtR+GzxatlYRD0wPcI14/8bA==","shasum":"ed024a4541eabc322981cb7607e143908f4abfb9","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597882871.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPcICCRA9TVsSAnZWagAAyzsP/iRxCShjWfUGoEfY7khE\njr+OTqG6lc1pitp+hdd1K3VS93OnvHlSE768cXp+SXFD8yPm5FCs5Eyh2ah/\nkDP7YJpXu4XfeS5Eg/zMqprcDVmRXrZ2AgZmWdYRJgU91PIF+asKYrrLsK9e\nIqSO8soLF9S9nzaSLQFzjWXYqyR88vYdUPlh0n+NlRJJalLgh7bACIaWpJXt\ng6cIsmSF31EXMjKjQ2/rftulK2cDILefG/3ZiqW6QvGuT9BDqBMPdOQD+NF5\nvfod0TVnsvmR+Zub1HT2F0GHwcHknWcOnpA3hxIHQDP0VGZ4ea1Xq/UPjvL/\n6j9yY6lGpSmNrOqePtlcv8v1dPHji3+Qgg9o4EIhsrahaGTwNL6iD+ZmTH4B\nIxswv5SgjUaz1SfBa+ieOK4Bby/dx8pYbMnLPHnqgkt4eVtTjRkx9rkuWjUy\nmXAG1knKBjko8Ghm3TDlJlejC7i4ZjU0sDmuBDlybsVvuX5O0BwozPY4K+w/\nuHoNsLeM8rmEqQokZjoGy40izmdh4IzSV2v3pYzkwdo6rqnwtn4ToALvJHal\n0EqJk/iMXQ0aga8v0fcDfrw1Ai3/VmAdGmyR/w1/wyLjLwl4H9tKsMzh/Du0\nWRCYUxAoHeUfimF8N1cJcJXzt7PYVp3bOOozoWMKDpLB0ONH9BmAfZkcJZz9\nOIoU\r\n=WkOf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCqCkvfRsX8/Y0TvJyNRrTghe70NKyy40EBgfRn5/MTRAIhAKuHENjdX8LMXFQeaY7G1/KeIJQpxEXv5ILTRPM+tV2C"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597882871.0_1597882881607_0.2427255630281746"},"_hasShrinkwrap":false},"1.4.1-canary.1597883869.0":{"name":"@joist/component","version":"1.4.1-canary.1597883869.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597883869.0+d4f4abb"},"gitHead":"d4f4abbb3d415f1d0bf99dcd44ca9cfb071ec656","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597883869.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-tAZFfIq3yVwefZOCyZLX306HJ6rwaWc4aGY2RmG+xX0CL5yXfcJ4/ZnDi266B1f5ob/uQP2gEoze430NTKRApQ==","shasum":"35f45df1d6a596a3eae0a2a7862f58cecf6f9487","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597883869.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPcXoCRA9TVsSAnZWagAAfJQP/25bKhFgLthdzsYu6B77\nITQl0CnBwLqF30KUhQCYI4Gq3f9wPlyGytTOMZuZ9bnLnoKvBM/045nZzk0c\nFaYqRHteuZyWZ7W7VluhRAG6fMeVSnJ3e1d1DV//S/25XhY9vHMCvPbTSDmZ\nsUXLU/m4CRSFMgZTWC3v4JLM/dA71KLNen7Y21qogkuJx9/2k/ImM3trorxB\ng1MXIpvkqgtVORUc4Q+/1eyx2mxNyIsLWxv6KaHiGSsaa+zdPyHWnhBrXhND\ndVSqmYcOc6dL3hAQhI/vcd4VofA8vOSUxP9PnGU41ax9/6hJ+MUpzcfuoKYm\nWUTBfZ0rhWu+Vu9GOAcnnAaMGvGi58wXp9Bk8o1B2Q5BxhrwumIRaD0T6zHk\nnVdP8QF57j5qj4/PRPY8xYKXnuopiNZjHUkUtkmnSFaIfqm7XidJd2CBspRc\niCEclqcQW+AHbR1IzuB4zpETEcyWsWqgPwqLJYQIk3tHdA3S/8G+fOwDo98t\n2YWGO9oc50Lp3Uw5kOAJo5jJnC4aMjO+XFkmdNf/bHdD9/Kh3kQzACN8bMAq\nTISwjQU9kybPxiKAv4JOWzhNmjckrifaMAXmPrUe95eVr1nw/6gLjj53bA0p\nj4GJfZCFb1Zie9KjHT3ZLn9Lgl056lgd51WYEXKcU1OeA7UMCfSr3or/UBQ+\nsxWu\r\n=2ieg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQClD2C1hbjncDpsWv27tHaqcZ761bo2Hvs2YC1wU9YJjAIhALZ4rRXXAM7AGKRBRNhOG7oFOM2JK8yP+Zqne+0hVMmz"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597883869.0_1597883880007_0.036648809261216275"},"_hasShrinkwrap":false},"1.4.1-canary.1597884130.0":{"name":"@joist/component","version":"1.4.1-canary.1597884130.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597884130.0+90822a5"},"gitHead":"90822a53dd7f3d4fd97d4829b5d5765bfbf97278","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597884130.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-VoplBuRClFYJa7HsKZ73Bet7VAE3dKzlbUN5BMFkdbjfZUWWAY+a30uMj/hJHtEy9i73TyasE/sWuHW8R/yZ/g==","shasum":"a532e264ef7d7176d2cf9be0becb1fb300447d3a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597884130.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPcbsCRA9TVsSAnZWagAAs5IP/jE0VKU9JG4iFJZvNpPJ\nkKjl39vLD+6XsTenzF6GwVixMudP/Uzn/ai2yj0Ovgrsmu7fRaw+mvmxf/PU\nPWk9HUtP5V1pvfHsaFD2KjCqtJt0+QNZd4uKVe/VROKkZu4U0DJfJBrTmKMG\n2KI8bNSsUDAzod1Imdb7QzEG459V00lN64P8S5oBYP+5lNeqnWd+iJ1pXIFa\nXq5JN/FU0//bRnOqECCbKQCwnlTF1BcRtg8GvxZpY0fZtBItx97R6O/pPejf\nfelieaq9zk1R3AkrWI06TQPS4K6cqfMV9muPhvGutKQH9ag9Ilj3sk7dqNQW\n+c2iswXVK6LYYzypeTULDwMJlXkBYlRtrXy1AROKj/xOYWJxP50ji3/BVfl1\nsV4wFk+MyfM7+I+7OCpDO2kjPgKtmJ2Mo4nc4StYk2s0qMTvPWskz7PJ1BxZ\n2CBhr1AI7ZTQYPlw7o8A9Alz5Z5UG6IhwHtJr7QQGlNHkcODJlJWNX0WauQG\npeYL+DLLi/cNKTplj6/m2Xpmj5BwJa3uOX3PUOllBR/ZFsKjFJK6YxzfJp9L\nrlLzN3jO6SYW8OAmXXibw1kFZeXXTaIHvOFEXkElCr1qmH3M3FXI3u/WcGue\nvNaPnwVJvydAb3N6/+bXvc94U2feyjcjkVjwxJs7ya7zBw+fiE6nKmgR8eYF\nSsiq\r\n=UDME\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAORYcPTktUcQGb+tHVaPt4fq6zjPYi2y/nE9BJPKScWAiBLS7ywBm06IH/cf7JwSByRJUCfmyYS85vYGLnqHc8rcw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597884130.0_1597884139967_0.5991493887976413"},"_hasShrinkwrap":false},"1.4.1-canary.1597925879.0":{"name":"@joist/component","version":"1.4.1-canary.1597925879.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597925879.0+a89ef49"},"gitHead":"a89ef492c3a2c4dba3f3f5ae54d5b7256cea9dd5","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597925879.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-wC8ABPu1iALduHzCQVC4+idYd73SCYhj8a5e8UZWphDkWW1ch0IbkOhK0XyOfV0YVsBARmgfZoJKC65KWMUnWA==","shasum":"245acd79b44381ddbc19588db687c43a42e058a3","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597925879.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPmoBCRA9TVsSAnZWagAAa84P+gNlLvO7mfaw1QtdM23U\nMfZs9jgCPjXr4JlOxlpuQDNVOLurS5q2MAaZr3OB5NVqkTskF0d3P/wtIKsv\nKy5T9AF3g9RUXAzekPQkssIu+9v/4tpAkcdFMrJy0R1KBGHnE3lwbZlmJbga\nBwMhqLZK+01ya7iJkMLxPv+InIZmk1lLBhZZ1njYMSLHWMt7bnjdeyT+H+By\nm0tGUAbF2XxAEqFigcbs63j3ldEERYLMFXaQqAmLvXGqMgwfaue/tDjORvdq\nKReOfYPLN3PPsNWHBnJuyK1QZ/svrACJcOVc7fLa/L7Aygc8DcTXQqpRY9mC\nvJlXek9lyJpZeHv/PkObz7Ipzn+0o5cfxPguPW0szsqyB5ultGH72VV9dX4d\nhaEX8CVk43f3HXrCBCsqKThfajz+S+1jUAVdGKPCM0PxY+UYx9nZxvDqXeMd\nhy3Pfq/BHRZ9wbpLz0gl1WbUOkaDsdUo+lYEAXMb/Xo7lHX0AReZojkHxm36\n7+s/RbR8lHqDatPs1GCSBSzxCX0Mn03tsuvsgPuOca3RHFTfRECypeMsTDyd\npjR1Zu40b7drDVvbZT2ApJBX55M2eL8u30TOAhJoyMid0kwQgQPYfkbtdPrc\nwsto8E+DJ5xBSVJ2XwuHZ27Mny7YZfAD8hJPPwmYHtxPdJbjRbu70JE0MfaO\n4S25\r\n=GZKe\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDZ2OdZhacYqFVh4EzDMgZy1/pk0gLhZ/j+7DAz6ai3TgIgCDidVFHoulIdajoYCErUM19DPRkdJ1DtNzGZUMp5okc="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597925879.0_1597925888651_0.19875571073923837"},"_hasShrinkwrap":false},"1.4.1-canary.1597933312.0":{"name":"@joist/component","version":"1.4.1-canary.1597933312.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597933312.0+09f5f66"},"gitHead":"09f5f660922ee39a19bde2967a6baf12fc1b7fc8","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597933312.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-H6OOSd8OVQvwlAJabb9BLKmeQVdg36lMlMX+C0h1xpDPi7hYIXnFTSCzfby44YD2r+6dhzqXRuvIDZHr0FZfXQ==","shasum":"cca00f35f077663366ca54ce7b8b4d3fc4102452","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597933312.0.tgz","fileCount":31,"unpackedSize":36187,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPocLCRA9TVsSAnZWagAAHn4QAJkSUgVHtFWzKdx/w1P4\nICsslu0LVqIQtPPvwTqF4yF8N3GJNSSPVfUJE7uNUfDrlcE/78HTCS7pRBiR\nDeJ4s8KuBIchTEWzVpT0KxYolKn6sS8sd8s2HIYrYSoP8/w7ngRg6jgYNu2s\nsI9596QEV59QmqayLLTiZsSJaSI5gVSmeqqFnmJ07D1wMRyEYP5p54CKZRrd\ngXk0t7lS9V0uFTgd72upvZJAvgehvBnkqdSaIxgCGbIil6uEqkO+6vDlETqQ\nhnMh5eNAeCHs3QZuxIz1oKPQiUiSXIaAmqXy93pH9cjxX6PQdzKDT5y6+X2L\nZivsVUOROaAptk75GoziEy7zOos1YvF4APClE7qXchLJjsDZwYsTMNcT8Lv3\nFtZ1K+qvl9TZsDVfbbd+1eIkky8noiSiisFS68YPw2aBjaoo6MIHw4htJ8es\nWeOFe3oxP3ZRDvzrTiBQq5jW8iA/NjyeXEX1s42XC19Ijp0M9JRZ62ucuzQD\num9c7zfjVZozGDMv1BVtqxxDzNjM4F6v7MqiNAJ3rCW79WL2Q/lyszz8Gyzh\nlEXXk5e7XN/UlqtW91dghsSiKQ/N7X9tT3mGJSXirrUrOBjYAzHmYdnGZ1Qc\nS9nH0+04drbOJ3gbTjSceqYw2aiFg+etURCWE0b08eUrLsQOjWqMXoSxE5KN\nexEC\r\n=oySa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC7hCySnu2qsbOTS9IPW7CaO4mvQAoWGpzGgVHmDP66QQIhAJ5IklLCCYVLDttzKwf8sbGwFjOM4uoGkGdmJgHiKg57"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597933312.0_1597933323266_0.37665193062184743"},"_hasShrinkwrap":false},"1.4.1-canary.1597940949.0":{"name":"@joist/component","version":"1.4.1-canary.1597940949.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597940949.0+9e72588"},"gitHead":"9e72588763fb0058844a9cc5ef0c65b26ecc0cff","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597940949.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-H8FOArSPURHgriBSQUbd8X6BJqKPIHZ9Xb9GhcxRz0pO6IfcWB2Ikx8FQGzYUREeNu5J4hztjxtI37QTX5sakw==","shasum":"40f7ec7ffdba216472d5d5a8cc4e06cbe4f78136","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597940949.0.tgz","fileCount":31,"unpackedSize":37169,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPqTfCRA9TVsSAnZWagAAv1IQAIEAfOiKnKNvCTKer49x\nBPUVHAaJVqdXforvEgLJoiR3cZ7Elj4oCpwR0D4IGsGMfBP0VEX9HILL8vza\nwrWcbzySpN91bof03nDUGagsrpTWrO+wbpF/w/YSABZZnk8vL8dn7+a2EZmu\n1dcsHueqh8uNT5U9KeMMLaWQ1lsd7i5gbIyHdsBlSZNS7PgMJ3RAYkFNwM9N\nC0zHgNDxG4mqpV3CIaV0EQ2eubFUbLQn7KqWVJ8q2cac86sMH6QUMs71s1Cz\nF856sr+psv53SdZxeWmGnhqdTDW0D2xP4SjPAYjTPKYmwkHlF+1rpgLk7N0V\nB19tgFaQhRaCSJQyNyVzQ8i06QHDtH9JNkuI639Az4MydmQDzNRmqr1uqZlh\n+2uDUYaPVpQBURDhBIG2Z00NmKHN9vo7pyjGBhaXGQvVUAv3lMZ3BE8kIBRk\nS8gWcAoLVcvc5QrCCqppeY12KK6OxXBpFAz4Q47lBtRf1iMcMXe/ac3Qn0aI\nGsG9eCpXXPrY2t8wI+tICm9oxn+u8KXjWARFsz6qR7Z7iTGKGkdDJPlHrQOe\nao34vfUwxXxc9TaKBta7hm12Bzr6aMIxP7cL0hxHWHApXj4mHboHDBpY92V6\nvMU/5If3dur58Lz3ScB3rajT2kaWQlAn3l23/RVfBPNITyrYt/5MpbudbATf\nz+8Z\r\n=FsS5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC4bFcrZrul68o0eaCH8eG8bhpmbvy6RhIztTBhxLKzCgIgFmbniMigqziTNUcQO4JRYUZFCorp2kYNvHlFwFBbb2g="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597940949.0_1597940959053_0.6608008906207192"},"_hasShrinkwrap":false},"1.4.1-canary.1597941184.0":{"name":"@joist/component","version":"1.4.1-canary.1597941184.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597941184.0+6213b69"},"gitHead":"6213b69795524dbd89c58e40a4e65047b58877ee","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597941184.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-+GzTvORCQVSWsUkquRmns7/zWAqZxTGls5cwo0i4WOohJPed+IXIXishMR9QteUuD3UDtpQ09+G/XfyBdJkPSw==","shasum":"d1d97c93814aaacbf296087ff7f5caa0a4c1bf8b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597941184.0.tgz","fileCount":31,"unpackedSize":37169,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPqXLCRA9TVsSAnZWagAA9i8P/j7tsCT7fTcofQNN6I1l\nyX/12MXrg28MPBIfzZuXLRLruYtuuX5eFWhWZwVxlc2hIW0WbgHacaXB3keN\nE9T6m51qdj8Cx7cBAr/GqP/pn5qc9gToBCf83zACsQruHJEOR0ICkVE2upkb\nU7bx9F/uI9e8UUeC7zT3RpuPNIVDxlZeVomrDoCuF0i7O/D24Xm4JoX7tY9r\n8wMdEgj6lD9dMyNXACbdO5Wzi7emOFhCbBTbBmh+ayqdhWgerpcXxJQaBQNE\nQzfxCg07kXVIDFWwMAKspgHR0ou52xEs6cnc7bBAJCfvlDknq5crym1iu1CF\nYBzf91XpCAvwDCNxvY5taZvr/j22X0ko+0uzZYuXVxZZuoACb1ctfQQe3sfE\nqGybzAohwxkSLSlDZJSHGIG4QJc3NfrTTi8mb9OO4PoYQUu+hBb9fgdaAe42\nvWvtQXq22pbfc23+vWDbefetxreDNK+fd9kvel2Bu1El3yARfm9cItSnr5T5\nm8kLQmfqUCiFGkruU8Y8+6u0gqIuecYc1MebvqfSOS9qe/xpPPxSFa0BYKOC\nWCjskGlLCtlZ3v6TF7JYF8VjePwuajXNTpivBMtpwanYmnwhNe2rsw7iHAL2\n+QnLLEcZ4qdZhIEqiCa+YxRTmNQvPWtX4TI1Lit5dipTHjOAD8DFzvMg8+BY\neuwO\r\n=d5w4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD9nmNaenXixif1tyaju9bdBLnapaKsTE3pfflT6CfXWQIgSSw0JAGBYKAjtXHVF6+yg7G3FKbLCoUhrLK89EDNS1Q="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597941184.0_1597941194577_0.7082266364904695"},"_hasShrinkwrap":false},"1.4.1-canary.1597952988.0":{"name":"@joist/component","version":"1.4.1-canary.1597952988.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597952988.0+f799808"},"gitHead":"f799808021e6fc1f7d7f6151c3ea3009ec0ee973","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597952988.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Uz79X7VYbyn9mNEger1uq42CWaSyJpjBMOQV5RBApEO6GNsGuPznyOUIl+6QQTNB900zj0D1vJiqq2yXhuvv2w==","shasum":"c3327721712a92c49a20d1c43618fa39869257ba","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597952988.0.tgz","fileCount":31,"unpackedSize":37169,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPtPkCRA9TVsSAnZWagAAZ60P/2VvMLu+BPD229rLeXED\nbBLSj32mQP7eWBYPNXu95mROlWrGG+C5zOvIMU0S1UVMtj0cD3FCdTD9FIGW\nWF4P8TXPvz243cm0RlIwBfuQE+Nwn/AbP3gphVvtuclcBpRh9oh35bgzSn7x\nyXd949stJAy+hXjbHDw9QvqdmAoz2kMNSsMJ4gVc/GURW/LNqXFDqGwjALcR\nePEQCv2SLvYVox4j+XDL/9dD5fCV32+FgNNevZV41tNLpQAVQhPisPqxzqeo\ndBlue0wKHpz9T4GZw7E69s4XWAT0K7/W15T0QGJJr28350P/qAWFEuOPyL3h\ngg+rKzz6+IhZbSSekOSnZbfgYug5zMyzRsZ+2vDSNZjivJY/+0d/o//vhtRk\nu8Td95JjVuW+Uew1bTUB5uabmTdFOG/1l1fXYmijmgl8k7ruNCwc6vB5z/Mx\nDEikldu4crwP5rCEuUjX0o2OMPK/cOVrskhovfcYEWW2HYHX1VlergvavNFx\nyiHzMhdx+iGjbL1Q22guPvFz138xiwNk+w8GvQnSr7RTA4iRBvunmi/21GCM\n1kPgHxOQrD4/xfb5VBKGip0c9tvoGmG/fYlSVVs1ag6rqVlTt1KJDIoQoFh8\niWZZtI48l4Q7X9CmDoBRmZYowK0bdpuKJhp0kY2ZhO7vP7GolFZPV1wrQgBF\n6V7t\r\n=wlyI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGIZqSKOu4rg9pusTff3JPaLun+RuMYetZzr4WtklSRaAiEA0qFxU9tjO10dM99khc+mH0GHs423Ezpzq6yx7eo2kPo="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597952988.0_1597952996355_0.7366715764868683"},"_hasShrinkwrap":false},"1.4.1-canary.1597957225.0":{"name":"@joist/component","version":"1.4.1-canary.1597957225.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597957225.0+c5d3695"},"gitHead":"c5d369532b6bb3c7f90672a27d5946ee83014f55","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597957225.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-DANZ7H311IBDJZUI8Z6l3nWIn1MMHBi+wc/kFvmXEM1M6/urPA6pC1il4fFoli3k6oc51bhYt73Vx6rHT6H3Fg==","shasum":"837442a5a3673224114d04a77dfc20badf6384fa","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597957225.0.tgz","fileCount":31,"unpackedSize":38264,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPuR0CRA9TVsSAnZWagAALLQP+wUhVR8c3zWczLKnNg5t\ncESHlYfRv8nF08Nk2sviRmD7Ue5UYgthD5gdyM75OtQA45I+KEqwNtQVdNOD\ngHzx7FmUuH3zbR52nGowLkJxtBEoG2zupj46asRKGSA8bbBRf4RR6/IyjoMF\nikBSQSZq3Vlov6k7UuWviN1lOxpwYO8HAQ1zxgBIh8f4EW/InHH02S/P010H\nz99eZfYu04BtkdcVTG6hEnkZFCdUPO8fj4Wtca3FWenMQLGK7K5Ce7j7Z+Wd\nAbRa0CbFiTS1M81ukhVEbUI8d/qWu5qnKXPgpzQQsBIHPCwi07h3kUKdSLU7\nCEiU0fjsYLybZ79A9UgSi3v2Ud2m7B48ckMakN1iDuUIhoZ+VgbkKhxuyDzU\novXgmkALx+VL0HJy9r0MrFh9fmvTG1HDdwl2z9xSi6vVCdu7b3SzPurr8IAx\nRB+F2ARVrOhIAzwrsqShgK+kbYejoF2ygE7/NCOZXyElOgLfqDTkTQ97X7Sa\nS0lPghuxCcAwxvsHVTXc6x30FAA/QycKzoSzsJC3Nys6cGrQJuSkQcOhWcpL\na36CH/5M6fMO/sVEfea6RYqMQuBqku3lYPalVGI4zd8AUI+fSYCBvDv5xJ9f\n50sItgbqovX9SxituJZ+lEJ5F19jQ4tbxU08ve/IpBquT2pruFRkFMK9bcf2\nExsS\r\n=witb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICrAGFeRCcXVV9eyl7qfQ1aW+NulGBPRRqJLFctvoOnYAiEAq3yB0Otid0H0Ywj7zR15ngsOfV8XaxdvvJ3qkxPM96w="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597957225.0_1597957235745_0.5663071905154844"},"_hasShrinkwrap":false},"1.4.1-canary.1597959273.0":{"name":"@joist/component","version":"1.4.1-canary.1597959273.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597959273.0+61325e3"},"gitHead":"61325e361dc9faff122f29b49fbfdce731df5552","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597959273.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-ZaNSh1rWd6VoR3iFK2n5rwWmRW/6bLnkuJRbO09hjbF9p/b5puX0pszUiUILRQFmryhTVNANFyulN9N4CkprcQ==","shasum":"e2b3199e2dd69fc141dfb5d842a0f821647194b0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597959273.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPuxzCRA9TVsSAnZWagAAwkgP+QEhVAYZUZM7yuKGjwqV\nZE6jBT4sCtoeEMaRWEiEGXxFnx1Riv/Qujy9JkqWHk7LYJcc194CfwmvRjBD\n4uxklQ1aHE2p2+nuqhxG4Vig5hpxs+JA5N5y48FvZjNbw0Y7hi2CnT+oRYQm\nxXC8rqiPai6BbC/qlrwgv/VArmUEYOfAcYVpSRx75vCAmkPE1esF9U1ya9kw\nI4Q3+/OsCBCI8qxWffsOanqVSArpqFxw8PO9SVhQSbz0A06v94dI+LEnY55g\n8AJFBjKwOdAtf4x2RGMrblDgF8rScpXt1ZAeo1UhdmRFBJkNybZ+Xk1QLy0x\nRq4znWrMYoloBznXmVLt+irDU0Wm9PvTZDXNAYeChKIIt3LjMQFVPWx0O/mb\nQQvftS9hLttkPlq0Gsj/TTYHq8tZOuKwo//l3WedtDZZT5AQsxwCpWCinuGH\nUlddiudz+LegUKBtoegQbZ+ZQs/pjwcUNrlIZ+HentHfjBdCo64Ibx9MiPNT\n3WHveM45J5Mc7bpjtTs8qccS3LNfpTZekhvMEskwkwrjQ9fNIPnqAJYRCTti\nO7uCWQNHmRnh9dxjl5000uaho8o5jDb9QJMp7lEbaKD8toxfv3hPHaMACEc7\nTAFclV8S4LaNK0llK7lJmx5xm5IpDSAEGlRHK7tuVzIqrZRYXkDlpevgliRq\nX1E/\r\n=xE9f\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCTFgKADLSaWudZOmn8qylk1ulNi5tQc+KaYxK8HFFlDAIgaNnLirOEC3pKbBF+4jSCZ8KIXNB4py2WprGzptndJrM="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597959273.0_1597959282670_0.5799721709290331"},"_hasShrinkwrap":false},"1.4.1-canary.1597961951.0":{"name":"@joist/component","version":"1.4.1-canary.1597961951.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1597961951.0+f65ec17"},"gitHead":"f65ec1791bdc0e44655e930fb0f498e404c84595","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1597961951.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-/KsD4AXsOPJ0iwpZTp3NQtXy4mJPziRNi0/LD4mzMyXaekcRg5XOkCdzkxwE50jIq2tfHgrxkqo701k4E/hfJw==","shasum":"fb3517656dee79dd220fa336b5fa65d532e0a591","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1597961951.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfPvbpCRA9TVsSAnZWagAAGyMP/0ltE2XUPgCa9GHjjlMl\n0vSs52+pXuzzpd8SeYgFx8WZYvrI+WH/qJ0hiYp9M4th1fXcvamy7Bkpmb8O\nTICiAFFrDPpWO8u1WJt879BZeDpp1ptZwB7+A0KwbThtSHrSvnBb0KRZUwQQ\nwV5Y7t0sQZsGV8+E0T7pw5HK/XB7coQYHlo8nX5HZwh0VQyHWfp/H4maHZce\nYd3BJuv2N3Luy87DqKjZuHVrVvgD3sYGZ27sHGI3Ywqmc4Iau7X9pnMZ/SNT\neldsg439T7d+ubVLmYKnsxspQPs4y0XxjIjoOMn6KatlsyPamMtgS+J6Sxqq\nRBQRiAqan1ngyeZl39Cy5ilJ+74PfQPg9Ng8eyhbet2LD9hBm4d9n8O7ywAc\nt5RmedL6T84uy/s4z5oWuez+h/O2G0PwOpin2k+GNGXW0MPLxsT13dlXaKZA\nOm+qGGnzCYgm1S3O7nK0oOAIXEb9giDzGrx7gt3JCZsXnT6mSV0md9qRon4p\njXt94IWU3mlsOz4MgG6iiBWPdD1gZk9UW9QuHEOr6IxU42j3Uwzb3WRRGeI7\n7J75dkgu0/wA8AdNyVWG5KSF6ZSyGBfVrwUyTUifNklTBH26c7ZrFC1yVddm\nXxPEvZCnJqLU1N4X4Q4LUPzMPER39G9lc4y53I0BtJzR490+AZXOY7ZKbEZB\nzNU/\r\n=wjO2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFxeU7AawccAul2bE3vFHEISmnF9nlfb1ktm5t7VFVerAiEArU2muOaeKp5QGbF42QubpO2npov9vcyTQK60Lr+mXwQ="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1597961951.0_1597961960944_0.9941263544063816"},"_hasShrinkwrap":false},"1.4.1-canary.1598023384.0":{"name":"@joist/component","version":"1.4.1-canary.1598023384.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1598023384.0+4577a94"},"gitHead":"4577a94ad8419106eacca689050bffde06d38f85","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1598023384.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-lTeqiYmRMi9O4S5MZCuOq2AZkAyLP88UBV8BQV3KkwHRDAM3D09mO13/EryZJxlxh5eyr/l7dNmptT+/gdrRZQ==","shasum":"118f28815f904e92eb4e47213ae9a0c53b8253a8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1598023384.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfP+bgCRA9TVsSAnZWagAAz+kP/i8ILH/uIrSdvrdh92OD\nQiF90Y+8cu6IeBRUuMV/v5nN1DXvui86eAhSUYwEnDMKkZzV2u4XwBJ+Njp7\nSDk09kNBl1KajV7VpoaLk2E55lE1K8jOhvTI30OE8Yh77THK4ZbVpXv7lNYa\nl0CFEgp2rpDXJYCcH9UEXJNP5SRNezo+nv8Oe7r+/Wq79NR/feTshTOKvWPW\nFiANfaXm2mTGnbABmTGNSaDpM+7bjPCSghBTG1vK1CnP6F6Js1h1EBcWtn8r\nMeZX6qaZx19BPbH6TyS2ON4x0VFib3SFnwqaY9d70CjBY182Hd+IXvSv4gjg\nmlIclbjlpoNdcxLWAacEhmAkDyyqgPq/bGfncdmo/gPzLp/R/l3zrwS9jGWU\n+1yzXHYiBkp9uwTPBKqg68dbUMKpVGW/+w8mPMAWUKXp75TMY18juKyG22NV\nlKtYtzB55ilmgQlOsunAEAz6wG336bRgRuHHXYY/9t4BapSh01vxOcCPoC9i\n3VHgtBMj3eRCyPBbNTDUAiqf/mz55xam7MLTn35/TrWWr6imeF8RtyVy4vIp\nzmHcMAV3Yq21Wj00D0McPalrvE7wCi29m9dJJW+COFMYBM5nR9hyPgx73g8U\nRx8xfSzUYjiudAHLEeBoGFO2ABflSsdRni1l49ddnO2pAYlRUzyqpsTotqzx\nTwyY\r\n=dnqa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHH2m0Pe6t75+0JgjRkIkdTbpz0jyTkr90y8qc1t7rzUAiEAx+EtHzAsOFJHH70G7KSBFF2Onlb2/e2biYxiQstttPM="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1598023384.0_1598023392577_0.3907178509624869"},"_hasShrinkwrap":false},"1.4.1-canary.1598040868.0":{"name":"@joist/component","version":"1.4.1-canary.1598040868.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1598040868.0+05c7d40"},"gitHead":"05c7d40c69ea873793b03a5e4dd728189a50146c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1598040868.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-6kpfuLf0QuYY0axklxm4SsFVFFSulzwZ4+wLCdwRkpzftg9jPL6HypERBvM7b7bfbcgER6AiCOxSRy388M8X3g==","shasum":"818a78573662199262cd8cccb6fa165f3b5c4d59","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1598040868.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQCsuCRA9TVsSAnZWagAAUwsP/1tiXFklDtJHfcPqLSOo\n7k2WcLFSj0NIpdwGi33Zw419UMNWgpKWjoJv0OotHtxqTrRMUMfTmPR/vHMa\nLFBZKpAvrNC9Ce+GWdr9VYUx9cCQQhr/NKf8DaV0O/HjeSe1j/jUvi4k7abB\nWFQQpJL6azJUeSo6s+XaTxMRGFS3UWATmxXLjK0D+yvXDbRmuBpSG/aa6lQu\n3p+bXQ5nXHh0u6U5m5la3LbIFDh9Wr9/h5PXYdbfplbhQ3Dn2ZDsNlXaUx43\ni8T+xXjJfHzwf5uiuVZEvccoW5oKCihoozrtpcWY/Uyzi0Skhdb/Z4ufXOqM\n1hxkCGKNbIBFnG6Lxh/brhcV3uO+qvppooE1uevN/b3xDSwXIhrzXZ8y3oGB\no1DCIyJNQdg0e62RMLzrD6IPq/VjB77BFTx4V/ja2UAslwSQYDiqVL9g1xlw\nJY2vNjZCPpEy1NgTl2MtBINaQ2vTJB9Tsi/3BEuWigyLUYUMrHcMhtzy0KrC\n2Fh77Wc+BvW71zv/TM/CF0kVcfbZjS/altTT50eqlif9yQoCbgIplT4j2yg2\neObqbKQUDdcaW7ng8cnAQRE/w//2kyfwnOmmS1ImzUcXwyj1gqMIDZm5vD6Z\nPwd1oFEYLdjAqaaqn94k2KAF8LPyiUn+F7QmcDWAustfWaanIzOKDwndxE6B\nnQGP\r\n=dA/I\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCu8jiraTL8DU2zmXb7aKAkR5cyfsbUirUT3TvhllH3igIhAND4BXIhd8JGXRcesC0CHlNuRB8EiI6M1MO7aNc/ORh4"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1598040868.0_1598040877650_0.9158279643681606"},"_hasShrinkwrap":false},"1.4.1-canary.1598041497.0":{"name":"@joist/component","version":"1.4.1-canary.1598041497.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1598041497.0+c007caa"},"gitHead":"c007caa28c7b0b973cbe41a2a0290137a98ba663","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1598041497.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-h21LCoR5Q8f1qbddGGeT/4S46WCU3OWcJI+wV6+LrIyhIIkTs7z1F8v/Alb1amq8RIcJyvREaOy0ZjQBQWwzzQ==","shasum":"dfe250f63ef8d594d754fc0999a441e6970bbffe","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1598041497.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQC2jCRA9TVsSAnZWagAAc3oQAJmcLdLbkzWfbQDZAsZz\nGzaXGxJ4Jh0MvVoARBOHpa05BXUrW8si/oYQYgNRa2cA0HsCqrgndBRNqsSK\nYV6CsZLswgVJPU3AleyK3z5Gzkq4MqlToCMaIxllCH8mCg6quVffbqaJQnvD\njAVCs57HTAZ+RNTuy2NsgfGoZQ2FcsZLRcEGJgCyS7M+OWKT3eDIqCZBP3k9\nkckDl9xOBR7Fxrkc8JufEBFwFr7neKi6PrSDfDT3Io7V/vT8jLpnOBJQle4O\nwhLQ6uPmkZdIsQEqdzdXHqknaYhWRm6m8gi35a7k9aGUGq6yzflD08kSbLXs\n4/aVUNXj5jKO01BZd9kv9SVSHoRGbVINwNgspN14/yCkXj/RGaYsyli1U8Yz\n7xClj++XkUgrJwhnpAclvzZmyn3zJom2HXv8P+hJmrvMu9SlKtZFrUGog7XF\n9/ud4ldq6HXKXlETfhQbsJ7vo8qi2W4hRSfSiDeGW1fej5eN3TXoIMWDXqAu\n8GaA80+galcIEYo8crLiVz7Vt//KeQYrCnjWSDzjzvxKN6h1QMTham3Rufn9\nuZR4tFVi9dd/vLxXhpZOwooSQX+QEOUr0w770Tx4u96ASRDPve5rMSjrV3kv\nMFoFLy1BUKDx03bXdXijiISVy0h2g6TPUGOyteyQr7hnIgovmJWdQEC2PQJK\nrkA9\r\n=IxvO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH4lQ2pLHxoQX3+VJpM+dUK2MOYqTfkfgSYhOccVxEnFAiEA3taolK7hVQOqliVXALbvv0b4PJxu8/w9QcjfL68qDqI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1598041497.0_1598041507224_0.9202033992896061"},"_hasShrinkwrap":false},"1.4.1-canary.1598041565.0":{"name":"@joist/component","version":"1.4.1-canary.1598041565.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1598041565.0+1f9ff25"},"gitHead":"1f9ff254ccc2ab5e971d2eac594806ec1310bcb0","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1598041565.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-wqk+aQFDSB5CXwtcRM7pAWjx51armg12vsQAWYBNdsXk1W3tkl0KMD2v2whw+Jgj91A7HJibsppKLECn7ncR0Q==","shasum":"1f5c0c98f3ffeedc000ceb4cb07915d29874f9ac","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1598041565.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQC3mCRA9TVsSAnZWagAAvqoP/ibfYqB2MmLBnZlskdPY\nDUUXcBYKiou+2cgC6PnP06RebLn5JJotUk18VlmCpFSLw2ZtuoJmYi3wsoes\n/1Pm4KY/WyeQhCckHfLk69WiWGYFPAX2b1XwETsxmxaaDqpVuoeKtc1g9/n3\n/RxylYlbADkniHYvkgqrNxYJjfFTveLDwyqAOAsi/tojqdDMl3ZM7tCFkJHl\nNkdgsnmQPOpo+Vhssf6WkMl2z4rJRzi3XLjIqO66qr4RquD5nOxhmD71lhVk\nPIB3joAsaiVE4NFANQ2YDxr/TJLnJkrWOaRZ+jzUpm+xei19dJ8ObXmFq2em\nu/cFBpY96L+x+eRg8+hFO+WY5SWfPbiwuSp7ixJMCyGxEM2JxNA4Nm0aeZfA\nT1fbKYjSAgkRtrTyrW1uIGSYM9LvjHyJcf+j3IZczfs8ApEEYtoAKq2CsvUl\nw3YA9T5152qRRqixcbME3E70yopulsb7og1y0s5iMAUwrJpBVaHGmeIa9w3c\ncQ3e/2hPCivaDaxkxWORUHcRFIVFFklTRxzANNlToEJ8idZw+XnahDr5CU+l\nqMlM/MXoJiSVWYcAx1gxrR1uApRaFncHm2EAQ4XULwx7SIJdPJrZoc9ub6P8\nbweQS2ps7Z+vL+mcAt3g8kwdNADMXVMN71ODkxfk4IaxlFfQRs234dLhNDSN\n7Wdx\r\n=M6Nm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD/IrQIaS6XdL+TmlMVuQnndSke5uwVKVZCFJs/zMcS+gIhAKCrHzHEo3q7zYIwTfJw2SL+U3xEMzos3HwqVz3eqiH+"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1598041565.0_1598041574359_0.560918024251126"},"_hasShrinkwrap":false},"1.4.1-canary.1598105375.0":{"name":"@joist/component","version":"1.4.1-canary.1598105375.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1598105375.0+23ed36e"},"gitHead":"23ed36e9e4f5350745cbb9f00827ce6d964dd631","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1598105375.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-FHMMNeoXnHoihgYQdJPMMhUiYJL8oSqngcNyZbIDFQMOivxNiuR2x30b12BVKhkfBqqSZlU5/wkeWTO7czRJYw==","shasum":"7314756a3382ff1c92aea27c96690c4c23d7ddc0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1598105375.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQScqCRA9TVsSAnZWagAApNYP/R/qLcJFDyYs77FY6scY\n8OmK7t3MLPoKrcz5LX3FgDNyhSnIZf26pcTqPPiSKrKdn1MVnIrcWczWMU0/\n5CA62GQD6Ib0CMNfhJ+nxw98o+4a9saOJo+e2zreQmtGYDy4KBtyDEz+H2xn\n3nIZLXHSpCxMIg3XFnCyOasljT9hHpYFKaqWoA4tXEWKr3M3lMxrhq15PJU9\nnbWXwSOlNaybcIdFY9I65PVRDt8FNG04uL6K2lbvv9GD1N7p04XISkIuND/G\nXEZsXjA8GQowpmx/IB7Q203ab/mcrEK+rmODKyPeqJbs7gklQN29TbB3yeWM\nypniusGn6tNqnMQAOHPvlW9SJlZGELBtaYc+xDZUGKJTSQSFukKtklHky5Od\n8SuohVGQOwwwvZeHEVrm1EdFvdFFh/hBtgvA5ZKpMCqshvIUdxhWATyHNvYg\nEVMg8XKkE5qdG9snE6PIgYjI6fS/awMC5u6DJvH40jhvyi6JNPShauvJ+eGg\nLj6tmwEonkmIAlDb1866MYD8bFFaiYb9TlY/tWDkFdU2nwyFz/hQXdl2yC+k\nVa632GLPAYs2HLgnKa61MpSMj/6z6gEsLg4cuZHYi42RlXgf0uMk6WV72Ig4\nsng0miZWZOrhhEJzR/XmeEBEUWAqZ2bg99v9yJ69x/aUeWkzCQ7Ns/GXzKwR\nZ5yv\r\n=5Jic\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCMqkuTPLq8v8qutBQSa4uuxuN4TglsPJu9A6BQdh/56gIgGLQS/ZX3SXVG/54No/XyG1tA4eAZHNdQ5WnhWHhvtf8="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1598105375.0_1598105385622_0.8053599514031942"},"_hasShrinkwrap":false},"1.4.1-canary.1598105395.0":{"name":"@joist/component","version":"1.4.1-canary.1598105395.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1598105395.0+3a9acbd"},"gitHead":"3a9acbd89b2e8a00960eda02b275499e4b63e151","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1598105395.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Ob3JM8yawrnzZmUQWwWmG1kvAx5f8gQ0RMgNqdsiS163Sn1L2VM/PVjXcPpRpxEuOjUGhd/XGnQWRqCwYlEXWg==","shasum":"b1c51e83d49ef24d796b030d91df28e05fb2f9d8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1598105395.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQSc8CRA9TVsSAnZWagAAOVQP/3PCcyLTDtzvuNmS26E0\nPpDRmX6BoDTjBnrHD/Oss4IXf8x1iOuvZ73LAu23A/u14kWGlYCuwfVmcWXG\nZ4bflXY/12TOURvVvvbYvp9wEf5F4fb1FOl4I5Czu47CwzGprDm3oOYQ02TH\nxWg4CDQeDrImn1W4SGuswmusd9OfK5j4ILeGN251L5MAr1/GFRAsnq+qID1G\nhQFkKcLSQaxrfbM91Xv1IjDhoVUtdq0WkSwJubiAZAqHc6eSeqs8RS1UNgE0\nnANQJQ3qASbBFgYW/6TV0i8rQ07iFuPCHaP8TviC9Qkq83y3e/yjKaS9002Q\nK96KiNvJX7RMSiFoANtGnW4mPekHqYlfrNebbVyMIZVzT8AbQoYmvZd7H78o\nMTjj9Edmj/lJHSFtsj/x6/NQcGRLlMMvB3vfKygJIHLqXZd3nc9EL1sisgnM\n+DAchgzEo8C7Od9Sc3YaNdQ+x2kN2Gs39XP6QLsh4Liv1BN2kOREP+eiZ7x6\nS0ELDGnNEqwnzXsGAiHQxAvAGOdOWRmMztTIMw6Ak38iyfHB9/fnrA2PD5EC\nJJDwi7u0lBBo++hXRCEtU+N6PoglXnkMv+6NY14DdhjPUlJmmMBRU6TUsrRK\n7gRLVZCxI6mN0wTSd/alILO6GQ8elU9iE4KL37b8YWmuGuz+5W+d6IPNGmVc\nASgO\r\n=52UM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHSS2ATVEs4+J2g0P7swXEjewon095M/6ysK8Vuqe1/NAiEAphY6hcNDvFbrBqOTt+W+ZEZY32DPTFo0DnxQ6N/8YmQ="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1598105395.0_1598105404119_0.5377257229034693"},"_hasShrinkwrap":false},"1.4.1-canary.1598155326.0":{"name":"@joist/component","version":"1.4.1-canary.1598155326.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.4.1-canary.1598155326.0+7426b83"},"gitHead":"7426b83a7b60074735e0bc596db496cb4c617eb0","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.4.1-canary.1598155326.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-gPdNIHaZQfmouXRcxS4o+HhVhq8nUaNGdw52NvUkMGWt3j6kMOyJFrZYnpxI92MCqrCZSFL/ZH7+IFK2r/elCg==","shasum":"094482298855f1046e6e417570f5cc0a700963a6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.4.1-canary.1598155326.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQepICRA9TVsSAnZWagAAlrUP/2bu0wJWIkJAsSPF9cnY\n8z0/gIX/UzhQYKBBHrD91T7SxaTz+Mi3jAEVxGT3HA9fKaKQRWXuCgQQQOfK\nYWV0xg7jj7sqYnbguWSdbM9To0/spob0Klfl7uEG23NaFyywFvh4j3Y7dVkn\nQNvftUXnzFuv/2/Ln1yrdJeywpqsmRow0Nk2BVbaAhXejnMZddSiCnF23Z3M\ntTAj7QX3Re7oJkHlAJOGQAOsUO/wMWWngrClIGGdP0ox37e8U1U6IsmewlOZ\nGtq2SyxEJSG8EwiSjhstU3NVNciMZ30u9RQGmSGhguRozsy8bc91p5wcE1VE\new/9u1y6ipQjqR3lpxG4eqmu1ccLmJeKVi54rmIKUwPNhgTofxyiogUSm6+T\nE2WHiWM9D/WH0QT30SJKHHQeVvBU1/AqcXSd5lmte0cvnNGV80pD8+25Do1t\niOxk32RhzTbLxWQ9orskQ+lGuyolapqm4n/jlL+sUsq0NVQLpBqKfmoEgI30\nTKe7TGO3IBd7oJd5lVsDICXtuMVGaW+2VZVR1jsS+la3/tADJjNXhWvrL59i\nUm6X9Nsqh2l8tHmebVG6bXx7GVSek/0dYMeCkFR76ZB0nGAsgXj4sRJmYQNy\ntlKNGAJJ4h2eEQpZ1FEqxXGIsecVmNHQz/N9Vk0yb3pEJGWE5lXd9+sj4YSD\n3G0R\r\n=lrX3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC3Eomh7a8+qfHKNalUbHZOaeFG6E/w8UXC5FmPDBD9aAIhAL8rGh4osl1sL6ttlLsOQ8OtEO2AjUa86OUlsvW5JvhW"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.4.1-canary.1598155326.0_1598155335658_0.9379504890508927"},"_hasShrinkwrap":false},"1.5.0":{"name":"@joist/component","version":"1.5.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.0"},"gitHead":"b336a12abe16abdcfb5d5aff5389dee9f43b607a","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.0","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-Oy2JeY5pK1gFl7HERxAadTSNQbaMhEqnYQECYTfbeogssCTfWwW8fJc+qkDp3M84RjgBaDge1HPXA4D+6nR8AA==","shasum":"0d2869d826c49951d7b417fab109972bf780bc2a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.0.tgz","fileCount":31,"unpackedSize":38787,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQxQdCRA9TVsSAnZWagAAzTUQAJGraMAw+8yT03ygnMg8\n9+QnVTE9/AtMls9qLgrt21rcvpp0fiXs0YoJbOoLsK6sz94upqs/aqpZQFst\nogZJvxF78qqPdGRsMVdumnjwdup3lXhvoLtruX82lzbmZbxPiPZXEJIPrSsu\nJxlbbMES8Ns+nG1vbfvSXMhcbTH9j+ubm2Za31hgeitmZJ87l+UmqmYbWeJq\n0CAYdoTpxK+j3D+9AnxQN/twu2bbpqVyUydI+dSm53uK9OOrtTNTUK5HHOYJ\nBoDHAeDt7G1hByq+4hzQbh32JvfNrWzCJve7YVYOrsKmrIxy1DrR5MM9wu8T\nvPLrkJ5AJq0vjgs9VoP0jESQppYyWmu49Z93JGL7RdQ7kYLqi1XOfC3IIeif\nNbcBlbcjCnaV/nJPaRpWzK8I/pVLSRW9g1RDuuECOrq+z70olBcJIHSo0jLf\nRROBhC9XKkFsTA7DB6DdPWqGtHp+jCzWbf9CfYVldPPOiGfzReIZeMBepjdI\nUmbSczXPq9cNjNGnz8aYLX7T/2zjsxMSn2MQX3asonR2XMto1BCxWe4YNM27\nmnNkwYj9APYITRzYz6yDFuls0eCj9WNDPc3NtWFbm0uyyrcLBGzFonWunyJA\n4jvK13WAz0IEl0N8ux4sLEdybZPgQV3qaA/bc+dlhBUXMIbS87oc8YXMIPmr\nW2J8\r\n=PkV9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFW89dSn7LmnbDj6N5KSupuXUEP9FS9xRkPJTupXGAx8AiEA1kyiYQlxY9yulMACfmTh27T9I8OV1RgvcI7IEPcy4rE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.0_1598231581207_0.4958023064711017"},"_hasShrinkwrap":false},"1.5.1-canary.1598231619.0":{"name":"@joist/component","version":"1.5.1-canary.1598231619.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598231619.0+b336a12"},"gitHead":"b336a12abe16abdcfb5d5aff5389dee9f43b607a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n    \n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598231619.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-vDj0BxauvcZPIJjsimxz9h20ApxzenjGbrcUIS1dtTe+g2CQ8l7wwl7M58MJdKMM7PK9XARKYRHIkEoYohiSGA==","shasum":"68442d8f27fe36aed1f64d54c5ceecb8fabd371d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598231619.0.tgz","fileCount":31,"unpackedSize":38843,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQxRNCRA9TVsSAnZWagAA0lEP/jSuW6CRe/J60gZG/66S\nWbR3hX35/Zu3INX/4HLk1fclI5P9suRhsTVKlKdstEQ0oxCvcMZ1yq8JwuPd\nB3HPYoH8uFB1uO/dIgjFyFrrbKMMhRwl38HGK39fwDMk1ymD7Nn/vASmtTb7\njIE3w0fg+h90+E8K0R2mk/eW4M5pj22o9PZadwPd7t/BGoU1qplDgPcpgspE\nxM5qoKQqt+S8ejYwUoCcPM0uhEMaP8QeanadAeadJsurzpwmiuJa0cuSaSOL\n6sKYYSM6aDFfAz4BQtvcfoGkRRM8sJoXQfcsRzOfSUKsElfZ+g89pgWRFWXK\n5TZrSBPAae4Ya6RN2hKCwtRuIQX86tneex8tPkxj+UGC2Pkg4lQZKRS+611J\nZHrIJBgRPaasyxCje/riGuPXGt4D7V3GgFIYlvbzrYhEL5rFuvxNLqQUqiiy\nyevH27jc8l08GurSPEbNmGUrUyi2WlFXz7PRzJf8bRO6zUU6LdTZTryAiSXv\nhH4vRcqCNvjwvsvg+vsyKHwNotpEl9+qO9Ew65+k95yOvdj4tKNyfchOlEIh\nfeexuD1NYwrXWXz481mHqDf0rJacWOQOzDoPSMVxf191JTI9tJRQ2Mwg3Ni1\nKln17ZCPlIbJseRll0IQkOLdlbUWiJleVNnRHpqojy55VihlRyq3Sl8i/Cb+\nNDCr\r\n=LdZO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCoAxaHbf78w+rto6tSizLo9/HyRE5FdMDfFifsziYaKgIhAOK83YTUTYreo7K3/7mgZstDyFzYc5XFEy7ert9vKCTB"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598231619.0_1598231628851_0.8886908176217645"},"_hasShrinkwrap":false},"1.5.1-canary.1598231857.0":{"name":"@joist/component","version":"1.5.1-canary.1598231857.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598231857.0+14901bd"},"gitHead":"14901bdfead269b5de4ff266d6f7bca14ae69f8e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://github.com/joist-framework/joist) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598231857.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-HlvuEgcmWzzbPfv0I7/fLKmTwAdKdHUkQ09GSpz4jm6M0YNxkL27o/thtisrEMsQZBVuXXZdksw0ZzFUyBEu0Q==","shasum":"0060aa2e171a3c2db9a47a54b9ddea3e46485735","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598231857.0.tgz","fileCount":31,"unpackedSize":39018,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQxU5CRA9TVsSAnZWagAA+k0P/RVBEzRYdX4cep1TDy+K\nf6pAbvhcsUlkp4bLxw4TCGtwFBTJqbvca2Lv5/m850E3a+nOJHLMM/pXFqYs\nlFAmTsnruSScJIwlB690DJOzQ4Up0Hjgl/inRWZM2k8QaYjV7kgjm/X4FUYX\n+wzFnQyjVVZKsloeRKg3ruIy+f+hBbkG65sE8gcf0TJHjhLa0ayvGvVp41fh\nzu1UXIA6DqmqwF4HkJg+xDqp+E292aB6MIcgBcUzRy0K7JjyURKXa0MY1oPz\nMMzkhNoGKfpQSHNdZ1Q13BVdJhqzyZbR8/ycNgHTdgodo1tyM+Nxfp/LN8Xn\nhWhdoKaZ0ySlOlltOa9zm/GHp3JvwPImGQXjg5ktWDY5roLIL0MtQWYd7rU6\nuWUJx/LMngXTgJQfO3JNUa2MyvdKxZ/ylAh67U60w+iAWIz1rFtjX/LDkvLU\nH2LHr9Wt9+NF7Whg2l8N90bKny1hswtj8rKeErIoL73nhBH0ksL5lrxWBOHg\nEle6ijaoGff11TdcNlYcRuZ4926R9SxSf+g7Jp8qvoJ5MglLNluzISzEHWmO\nCwEydL4x1SquuWCcEKOSMtFomJaF/eJ6I8CxeQRkYNWOIDRchUJtqqutlaLB\n+exHsmcdwefE+yZ6mRzNWGNU1XQkxQxKZX0rL8PmPnqpMVEfo3lmQSr5Z6IT\nKUbu\r\n=4FEm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFTOlOw2cajglvQJsd+uRtA3pdbVXLEr/P0ESvht9gh+AiEA1DQYiNEjBhVeKA6qOTH4rXM+gGalNlhfjdQorma3j2E="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598231857.0_1598231865544_0.10960348121481744"},"_hasShrinkwrap":false},"1.5.1-canary.1598232026.0":{"name":"@joist/component","version":"1.5.1-canary.1598232026.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598232026.0+c8ffd37"},"gitHead":"c8ffd37104b97b8ed3cac866809823028dcdcad7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598232026.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-oz7BjLlZIp/YOGqzWKiVP9YI7YZv/wI4Kc/PglZe+1FPcVRVTMJFGSjkl2J7ZQ9SBRLmdM6kVoIkAs79kCVdjQ==","shasum":"2a6acc237c4ced8dfa90d9abc91ef4ab57ad5d06","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598232026.0.tgz","fileCount":31,"unpackedSize":39053,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQxXiCRA9TVsSAnZWagAAexgP/2Q3aK5PiXJ5Mf8C0vyY\nCEkUZdEWfDA0z2ngspNpP/NKc+rDFUmQ1tLkp7mpNJFU2Jzt/Jk+oUVRBLsY\nq9PFa8dQiJ8ufxYnxmV0K3rj8UwH6tNrvaooTH70lBM3D6LfivKciBp6zMRY\nKwmFTGIomxnKPGF0CyhDnXyREZtOr1qQUcN2ywe4xGWk/USVk6QBAymy5RIy\nTAWVc8KQ9DLVXPDnkcxjsW2HubJtF96OQdI2u9Bc26R8Hg1Sw+sx/UBWmztn\ngtKTgmKW3ZK8PkLcBfkwmoUYw3JcT585K7/eUMBgJlRBKAZiwN6A7twP6KUT\nYkuglNKVKHZ7waVG81ssMoQ+oVUuXymjCQ7oUdL6obKcbKDytDWdQcmkOuSp\nC+DAfXxuokK4lvZJJi+Kpfre2b5Oh34IFTZqeqrEl3yky0peE0KTgJws3Csa\ng4QoCRbFjcYoI8x/RwWzG/WF87wZ+1u7H7Ks8HvnspEqXzHY1iQzsFT7sqzB\naYhS2oVvcgd2TdWQiMulrkZrB1osK2r4pSLqSkfsT/eQyz6CWS9P3/SwwYeJ\nAw9r4f22ifK3LPbS+TFj2he6PoOx+WWNYpKcVmjptDcvVS1eSNkiI8tL06eL\nui0IJTBmCXbnvJJQ0moi9R8NjO07NvIanU6vrvNiMwFw3cGToExGpE94p0Df\nAY5z\r\n=TCPg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGvoT9ni8tMStID/wyzw9CJWSFNrUHxYEkdHA9RH6EmNAiAd3e72HaBg2esQmMBAb86tZ7ym38FUCxXbXqkNpqiB+A=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598232026.0_1598232034185_0.3934644565808483"},"_hasShrinkwrap":false},"1.5.1-canary.1598269988.0":{"name":"@joist/component","version":"1.5.1-canary.1598269988.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598269988.0+d1255cd"},"gitHead":"d1255cdd983b16824aea02b6e46e6a5808f12e8e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598269988.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-PR5p/UqttHT6xDQdaDO7qLo09Ni6c0BQHBng1/jPm0vQJYS9GEPHylyXz04xgU3nt2OC2wooJFYdPtXPN1kbUw==","shasum":"31966f1eb48354dfa0cce9e335ba5c1d38126045","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598269988.0.tgz","fileCount":31,"unpackedSize":39053,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfQ6ouCRA9TVsSAnZWagAAwPMP/2h5mMyTJYZJzN8muxqx\nfVkpTkiYzTb5jTk3x7F++Mzij0pCBhYQIJLxSczlxT+4J6UNGWmoJ0Jcpx4i\n65yiMeJQPBghNSd9KqQtS4p4T5KLgyrDE+EMVJ4IvDBC8s/ODI5O2HbfFLH9\n0nPW92ywiLzJyDIgoxqzSIrJ/gq4/4+FhgiShtqzpqq1+JYTQHzcLypzLrQg\nZv9tGpCTKnRK5n44mXtJ0Xl8X7shzxSgR1KTZwxeUt7clNBocaUuRSkdNV+e\ngMp6XnTeQePLgJ/x3WeWZ1irhEOVlEcRe+YTRw5ztFWXTau4q6EIziLqm83g\n1BOAK9PdPNE8DROCHet11NoDNpE5F4HLqcLjguo3SB9zjCYE0HyULLjuRzTE\n30t4wFbUCiWuJdMaNefx3e7uqREvrGGJIb8VeIWkuGu3sjt+RQAld3BQf3Mh\nBh0tYArK/C/LTiYLGrT/3c70VG+zvoFnhN+sxkTftXcpRiBp0buK9N05qP+5\nEsJjOt1zXfjUqoMenXzg/7uGexcIAZUCVjRwoargdlspvh1m5mie7RQSvX3y\nglhr7YzWIsAJpgFlzF4J4Qea/uLddw0wG/y93Eqy4spCKXKG+5HA6MQERD4B\nPzFaVzKyhGumTglqD5uFcgaCc2CDPcc/y0pv+aE/+p2A6/inCQFGIV50B9fy\nU5za\r\n=JPYG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDKhikuUdNX881swXl24/xSFFw70XkMDS1XgQFEjdoemwIhALYAaLRB20GaWFpBegze8oIB+S9u9XAT1GEeM45W30+3"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598269988.0_1598269997932_0.022362682806287948"},"_hasShrinkwrap":false},"1.5.1-canary.1598357339.0":{"name":"@joist/component","version":"1.5.1-canary.1598357339.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598357339.0+12261db"},"gitHead":"12261db7b4afe6e5c5558fff794d53bff5a215fd","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598357339.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-z+5gcyDl8xQvyRy1KPEd13W8aooizl4Xg3zsZTsm60LKp0szaMopZWZdVm8Eka1g7SgLN1OPPejofoVtQ7MTGw==","shasum":"76e35e5191a0531acbac180c1dbae0bca3f85304","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598357339.0.tgz","fileCount":31,"unpackedSize":39053,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRP9lCRA9TVsSAnZWagAA31MP/ic9gizddtbLkOqBAx5W\ngb3j2udcyfljClc1qzsrIENIcCnyLalIniDfxvLCEudEBtSSwDEHVsWHBONZ\nF4p828DWA069Qd1oOtMmy4u6ckqFe7D65XPY7sTLXvYp+VPGLHIi+UnzJQV9\nwV8bbr9VQ6HH994DdXLStQE2/jR6az5OnRONHd5Rdo/xs6XmI2WjQbvhd2uy\nqGTzBhMjB4wBcp4AzubXWOX1x+tf/n99f6WMZ0HUbX6xlTLYWjseE9pf8ieo\nyvfYJ7C1/j0IN+jB7f/g7m0MKQoktQL3U7V9nlnjiD+6EKYyVm94ppoM2TRc\nJQnN5uJ/wefGf3KWCtPcgLVBuLPUUECb9mYaVoKxi4SM0B+ynKaY+QnUVCFk\nZMA4kOLRSmWfYjwQVQ1B0Pv1OdE4x4k/ENf6WyCl1/J6DF6GehVVd3Pd/tu6\nx0rx0HE2m0bbKiHW385lN1nFITXDHHREWgID9uSYMgfjNIIQpV5Wq2UbEdpV\nrg4GckqW3qKOeVNEizEKfw+MLS5vbVp9cm4jrXAcgGwEJ2JH2SfJ5fvw4jXX\nTJIJ+vK65w1KJflOYraJirL9MxFHkBIPxn56apTQc7bJrno4fVMaxBmxzDNQ\nV2cmYUbZ5KVHvCrUN36gobZrQjDJVJjYYR9culUZ7m8Sf9LZXHiXiu+IFVBI\nbhWe\r\n=TiRI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDhjAwwyf/oUz2hz04iiSKfuIx7zTjxSGJ3ZWAFM9QDSQIgAtr/sUw1aACY2TaVgDVDRJ87a63WVUsthAmVLVY9Chg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598357339.0_1598357349320_0.26547868203935554"},"_hasShrinkwrap":false},"1.5.1-canary.1598357359.0":{"name":"@joist/component","version":"1.5.1-canary.1598357359.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598357359.0+926b2c0"},"gitHead":"926b2c0fb939115bf5f51176c600ca524eb30cc6","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598357359.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-LIIfLBmpnG5w7rxrgurGIHsYVWITY0+N1hkB6PZByEcO90vlgCgk45hj1pdHvmaTyfKzfH3RS20kQUtx4gZNUg==","shasum":"7e1a7ef913947d698f1cd773761be86554f6212f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598357359.0.tgz","fileCount":31,"unpackedSize":39053,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRP94CRA9TVsSAnZWagAA+joQAKUtE56fcHpuhKeG9e2F\nyTy+68HijzOh7rEgE8yWFQej2F01oo+pMvhhIaLyhFY+DdCTtI3bbdredqge\n4kAZ4TiJ6VI9IVZ+lH90lLuJ2hGPpju2O/Xh9lcqx3D5A3sSR4XBf25SB0fD\nk5QxMVzQR9IZ+e83YOmp4vdYVGuyhDt+w/giibWE2SqeOPRdUrFKkeuVkDr2\ntL7bsrnkPsAfCIdPjQ+LivToV+YGBKfB17KvtaVYrqyXfwx9XJa6zifNVwJz\nXjQp5KZtOmiY3HoM11yyHkl7utdJDimRf9ssfcWYIRGhPMsEpbxR9vcAKsI2\nv0oormC69Qdh6bLHVfdS5fK36b6PyojthbLodZqXwnR1SDq/H0ysN7RJ4wLk\nC0ie0wOcP/B0GHz8Moqvnv/SF52/MhPRt4jwh0PAVD7zZ0Lh6ZvMLS/czAwL\ngZqGwxwBkNvC336CeLSKaA9w+oxZlIpeuRCA3ABycu7tQjRVNp0er7wqoOPC\n9qntmhVKIqUUrywQqkIWyb0lNMAcUp92b0Mu0B1k6bHVKerhf2ARAdWNxcTe\nCBqmVBoGpoogdGyTmv1sflYy4SGzp1PrRKiguHoV486F2NPNOit558iXLsPN\n4H5VHR+6rqA8XcDXs1pyvyil19sfKSlH1x1Tj1zVeJTVOrO7ctiGqmJnIXh1\nHnGh\r\n=TkHo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC5qG5MlZZje3j4lw+qoMzHi3D2u5GXJp5RCREnQeSPBwIgKlt6vQ9L5VeXnB3ICrJHtA9X65oivxMrXvaWqIp/ZAk="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598357359.0_1598357368168_0.2993815860118607"},"_hasShrinkwrap":false},"1.5.1-canary.1598369528.0":{"name":"@joist/component","version":"1.5.1-canary.1598369528.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598369528.0+427c1ba"},"gitHead":"427c1ba095b253c3e6ed6989dec86caead933607","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges(changes: PropChange[]) {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598369528.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-XTBZVa4VO42C9IqpXwk09SFmwhOx9VHYNOPbaJ8Co8bQL5r60JgUxZWqFtC5cXSy+8LWWeVOBgUcvfMJqCVqgQ==","shasum":"3e5d15f8b77b26b3163e3ab285ba095deea197db","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598369528.0.tgz","fileCount":31,"unpackedSize":39053,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRS8JCRA9TVsSAnZWagAANBoQAI+aPwp4ydM2TptbhkBn\nw47iVoddBuynpnA2MypehDjyK3FP3/4QxLVfiQYyumckQjxXItzpwIg5ItyX\nmdPMeJSFkrhDOgn4dHRz+Z8piO0HIJ+Dl06sSi+xI4bMXDioA1VXTq2Cdwyz\nfMYgv/gePW4C4pDCCnNL/EptRu+LL8/EbCIg1VFXHpTNhaCXooJPPLKpBiuO\n6pwLpBoIG3Ji+7rjpTUNM7r4wryJKF8aAclovKa4q423Uj1CpuGv+yj/rzn9\noYjxZrkJlSPP9GiIebToxn/kVnIYMPSVIHf4bOM/zei9kH8wVFU7dMcrLbDa\nAd2L6VqwFYF/hwL6ItghHO/fdLzaJf/b/ONfPzji2zjBwfdVZ24az3tGzCOg\nuTCQxCDzZ21/HbISNlwE3YqAyEl7Bbf1jI+2WCrQM0j/zrI3aAeSF3MLF9fL\nAwTJN1TCtfLUwWdQKLPH8492qTjsfESPZw6DNnznT41wSvCiw0rOa7IJqYni\nRIW5/fQJqNm80U8pkpsqJqAcpcFv3VWgfArxmSTIT36NoJPC6Ya036MNDGD9\n5oooXZFNeaS8QPXu8DjvdVMRLl1LPu0mvJ4OpfMMKCFNXuT4KSv2SmQN6Pvt\nrDkmc2Tevqsa1M402w4XI7xw+jnr9bGQeIKxaonWs4/MQw+HbM2ZyCCU3zo4\nqOHb\r\n=93ug\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCnKpaFJMVfXt0xzeqrZOWiEqv2pTcZ+eGUSANQKxpHigIgSzuOkYCY3LqEoHtYA+zvTPbw+Gfji8DoYjJaO1l33NA="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598369528.0_1598369537983_0.10965717614896953"},"_hasShrinkwrap":false},"1.5.1-canary.1598371506.0":{"name":"@joist/component","version":"1.5.1-canary.1598371506.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598371506.0+e98c506"},"gitHead":"e98c506083462e8ed18c8c29b221e12b1a524bd7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598371506.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Im0Syuxt4y79gpoziFn1yjlBfC+tG85wMEktan2dz9XyHBWw7YSf6jZkS1uS2f/dhcGPGQYXfHBfeAA4Bh/L1w==","shasum":"dc1db2af820ef5f5b5d65474dbfa565035eff50c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598371506.0.tgz","fileCount":31,"unpackedSize":39796,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRTa8CRA9TVsSAnZWagAAUbgP/io0AcxmzHbiTBjElwSO\nl8Ph6mx2kGjy64ASC66/rwyG6lkdjuP782vSq4emBC1zqar9GMYXFt3uvMlW\n81iExivlsP16gfCJ7yY2rC+Zs1aXveFXQ7wWtAMhgdCoZt1lv89GkWI6ZQ1y\ndBhcLwppUfRBDveYI6wYn9JEJFZAlEbyRepE4KQYRL2bB5hrlv3JowcjY5Co\nL0N2gckzBir1UuSwspssXd+/G/cJzFxEuLuroBYL2q9ptd50jyx4ujSsqAHf\n1YKGaf951EVId1rAx9elFkPPfiu8CRCWrGAx6+SON+cNXQFVHJEiUYo9nHlA\nTQJk9yZemR/GZEJfWV+CWeYNtknB1oYSmyQOOKZ+jw/02T2Em6+W9ToOhtz9\nJ27mBxjKRWolwypRu91Rjto7ywlJjJaII27AxsCBjvl3vLZEwCqqeDZJE70h\nLGUB4vkObe7cxMWsGvqXliONGQq0F9uEQ0gSpNIlqAvhULccm34N/i2+tSZN\ncfMdPYhbxVIbLuJODQ7udBxXG+1wtNkaSceNW1aS8DdR7gUwychfZfoK0AKt\n27V+5aUCP3NFHYEYmeSFGcOv3c1GvJkprcQ7pARqel7ic3pBVKuH/lrsEp1l\nvb1Vpp1IGeZcgAvluriTu7cNKkL2RJep8qINsSziXYn/RWHcIi8KiIMny70F\nnB8J\r\n=JUoA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGt8Zrqd+LFxa0XNBmAOptckzNHxhFmbdaMddvlVI+NJAiEAwNrxwptx6k8ZBqa2hGzcim1uxQjG6UianH+WuUIX6Rw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598371506.0_1598371515570_0.2193245486247255"},"_hasShrinkwrap":false},"1.5.1-canary.1598372767.0":{"name":"@joist/component","version":"1.5.1-canary.1598372767.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598372767.0+4f2d19f"},"gitHead":"4f2d19f637d355e69b2bee5b6735190d9063ed33","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Props\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598372767.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-o1UOMzD2Di01gzBipfOk+hPYLqduu96J6Iuu1ciP3YX04qbkmmdJ/x3YYPvz102lK4F2y/8F+aKt8od5fl6tiQ==","shasum":"60e85dfc3e90ac3589477f588d50763e893885fc","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598372767.0.tgz","fileCount":31,"unpackedSize":39796,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRTupCRA9TVsSAnZWagAAkJ8P/R83H1CBugPBAHZ4Xsya\ndFXnIhBwrQMbMUOb3jDCDJGvNTeYqrQgWx2T9ou6A/vk4nXrecmRpLu4GKWy\nVlpLVjci7gDiCP3S0AOHQjjpFutx5V0/v2EznspjyiwI29cXSfvGKaFYvJFx\nw7Lli2K1sxFWSxT9iTvNlsVfKwImWjx87n8gULNkwIUzx06P/yMPeMW26wzm\n18Z5MbWC1iCDIR7iexVC5rPdevzTT0pwhwNa1cpacAzErmuOUf22t8ZGay2T\nmU9x68A6QuXVpfdnYKWD5/Yq9DIHX7/0/EzJVVqgD5LMzCp9L22ceyIHH7bG\n7ql3SA7Ze6ZXPQja02GdXspGvE52hL+Taky1EvkVx46EyWKk1d9lXSDSvZYj\n2iuFxlNsBaU2mMs12vqD0p0q32s8It3ZrxGFzcntnoGo/nLQ4ZnLrhWEdYSw\nsupqBYMsaGA5ZlM/JjzthuXXqgf/exdAjt2/oBNPsS5sX5xUEfB9D2fuiIsU\nPRZWOEnHhyweE/MYxSxdNeupEMqmfQL8DBnLtqxVepd+Gqo+vQXrrZUZ2PjR\nN6UApF1NyphEKV0ZKuTFkZEFWIIwEO14ebvG3L3qb614IaC5+V89AzQNTvv1\nIcDQH1p4HSCCkyjdLuqotCQQlewfLCQkpFA1c7cFy+q6jnbsnK6NmwD1Efn2\nfikn\r\n=z820\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCsz3B0ENFJ/TfFbEH+pEyJL22Www2froy1tssFxOTgHgIhAIJsaFGiOh2dE66VMxorBQLDOmgZF38MnOwUHCb94/23"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598372767.0_1598372777085_0.5111990385616516"},"_hasShrinkwrap":false},"1.5.1-canary.1598380441.0":{"name":"@joist/component","version":"1.5.1-canary.1598380441.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598380441.0+2ca97b6"},"gitHead":"2ca97b696e3a812bf28e0e116d2aae42ade7ee58","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598380441.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-DtxpTTfDGRfOl4A2mXoUxN5Td/kbmUkcjeInGXz7/evCB0ykk0CB6T9n8NJDBK0esDCnsW7JueHFFhF4BgEbXQ==","shasum":"e061568435552943be68ca651ae7aea4a383b514","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598380441.0.tgz","fileCount":31,"unpackedSize":39801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRVmnCRA9TVsSAnZWagAAgvYP/3N1V3ZUGAVosZTNTe4I\npL/A+ny/mwvR9mJ30GmGGsS/pFx8+CcwVI2Vyu+lpgnA2HUOova34k+YwL+Q\n97HH/LGYpAZFWlPqf5eAU0RQpiqKcN3czsUixd0rniJjguW++fDIvGvC5gMk\nY0IPScmeujkRNhBevmOJOjUPaLRs5SNzHslgsTGFtPhTcBkFRESgrDRJhsDi\npDQAFKXNLWr+vjsMNk96uqIbXd5uSnd6SU1PFnxESkDM4qOs0xbUfmk2D2ot\ncvYDSU5+ai1qTZgSihpIBsQ+sJ8AxqdxDVJXUofYA07XSZaoCKYhfht92Ek/\n0Gc030++fGBc4wLXdwZqdAVrH8G2bsUkh4fuZuzckamHaIhdNPtDMlnfaBqD\n+2eII7fh3z2Aw/21M2ywtSzY6uYahgQdSfBRV4RukzE4VA/KHFMpxkZVvMsi\nVYCz7lSrqqdI5pOfHjeyuvNSp8BAw9zO1VROVcJpYLGtnqYNgLYtUCrpRGxy\nvocCgH8j5PptESTXQJ1c7m6ihDggiEO+jlK0olbC7EjGzRavBf3OV5Q/mcNF\n+RdjtFdA6yTbQgU7FU9WXzoSnG4N3K+Q3gfKcMnFS9+LCaCJtzN1/BJ5Dt4Y\nt+nmOzJ04pnSJLqSE8MyX4MryWzcHpsfkSKl1ZjBGq12kuEyDrE8qP1HFXnF\nV+Bz\r\n=TlAZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDiTZH0Rao+JwTnNx6xr2axVDyQsqr5zJBCDM6ufd9p8AiA7SWx+ES5UsWmmV02JNPqfvCMb8SHsgCG4bFDYx0/R7g=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598380441.0_1598380455227_0.6701613636180752"},"_hasShrinkwrap":false},"1.5.1-canary.1598442548.0":{"name":"@joist/component","version":"1.5.1-canary.1598442548.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598442548.0+7987052"},"gitHead":"7987052d76bef0762bde43d8f58b8380ab48cb0a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598442548.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-G3FM8oVL322fsoM0SgX064gFOdVzhJ2Tn84APBNXy6d0GqcT3lJCi36flQkBvFQ0nP3foo0ZLQuyL/LnyDyWGw==","shasum":"a2a2e406706984cddb129f555fca543b47928977","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598442548.0.tgz","fileCount":31,"unpackedSize":39801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRkxBCRA9TVsSAnZWagAAuxcQAIuMd8E7AM0Bws8/p40q\npb3a26xY0Zhj20lQZ6d3671joTgyJ4egDStYoM8DknFSdqegQZww48Ao0pwj\n9Bhxb/EkFHZzA9D0D19Fd1GMBpRJFzNuj0Khwr+N8ubxoC9icOAEolZN6DkL\njFBoXArRvWfGUtE1/xgXt6PO3pdQr/nSckzF2RVH8Sy8BCf5UVWnFyC4WtwC\nQbSapCJ53QLLnGnk6wVWjII105ST66wL75F6V2Lx2Ymm/Qf05sW7Y5GiBGHy\nIqsy3Mzw16E38PCzJTHetKATC3/H9v3NEQYTDyli/FmxDHFgr9hLNu+rotuW\n5rB1MyK8Nhqj/6dyi1we13IKVNxhkO9BBAHEKkab3B/4Fy+wl9GgK3Rg12Iz\nNTKf+ciZ8gjNZEsSMUkWen9JWsOsNEMGfKvsl9A/a2mQAvTdsa3ENUouEPXf\n2dpJ5fjt9IpkxRPeI+j2oIYl4qqu8X7PsXy7Rv5iOFpV+NZhdFmNWIpl8W7Y\nNKuVAzJAKApeaoXNdfKuZp+5CeqO3H6Q4YDANl6U32fj+7h7v6X9LZSyC63t\n+FnE+4bs7R7eN4WBjseCZXHSHlCs1EVoh515kSFHCN32fPvfB7jFeMfoCtXR\nwCULkozHx2yGovy8g4T4AKWXCba6JGwEgEwBwxBhWXxiU9wc/ukxWXWbGL6B\nh/9I\r\n=IpoM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID3lRuJ0leBRiJWDn5H/anKZHuHqSsIqFXF3mgRmrSkXAiEA2SbL0c1dfNzVEOp6R61fRUNwx/qMlVErJzX+nuqa0XM="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598442548.0_1598442560730_0.6898392222111107"},"_hasShrinkwrap":false},"1.5.1-canary.1598442904.0":{"name":"@joist/component","version":"1.5.1-canary.1598442904.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598442904.0+d8f086f"},"gitHead":"d8f086fdfda068e20265caa2bcaaf3445fd1122e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) all(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598442904.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-DFhAKGdxlPwmcCCg2Yd6xRw+6sx/T6lB8oggCs3xdCCoIYfM14WUEXTkHqaQhINGu4shxFPePNo2gYm2GJD1zA==","shasum":"6caf25787e321eb005b7232c176b88fede1147ac","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598442904.0.tgz","fileCount":31,"unpackedSize":39801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRk2iCRA9TVsSAnZWagAA87EP/3/tDv0ll017LcHPfNSE\nCe94t+5UwkxSPly1hCJ+FzLgQEWUukV8FiQzKEuPeINbD+gmXxGu35JbzQ+D\nwLrJqT/9VHJTZQJPlO3Gxhp7YuSaPal+9/wGyhwoxm/a5bUYez5Mouq2QCvr\n8MhI3xKSJF3j14U4bOWSyunrzn7u+Ss6MKUAN1ha8CstIAr9SOHaNK/RBcDg\nkadG5spTDBNLT1npbuyYrVL4YYQEGdvQBsKl0f/lg5LB3q5uV26NDtAoP2Ea\nlBsFJZqyxWMLTB3svOiiSgZjSvrwgbiuCG9h9147HtcPCNF+AEXDgKb+yEGY\nSEnXGirX+5Ouh3UtutWKWJuBisBVhy1dQZeRBbgQu4cLTkGToTuY6FpuQHYj\nSF1EPC0Qdk1ZWSFbWi+c8SV0pGJPosXC21vaYG5XBNFkkQOIF4B/2LWdXgx+\n/fl8rq+kolbAwb9nPIz4vB30d7hU6JYoiGaa/HaVwASEzQHbPM4Tk3o/Ki0F\nVCIzkgniD8JyZmmX3pfNgUQHouKyt6oonSX6mil1SrMsKKKPJP+YPWoALthS\n5hq1lHK1N+qnAgJy4BcQN0iJR0q3k10g4psw+58yc8At6QwgidbRTKubnGBc\nTcjHrlSKGw94A/Cq1MXex/sT8IgwGLTc7Sxqf392BF7HiYiON+MvTjwCYHK0\nw0Qx\r\n=2Q7M\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC4JX4G3txz17ueJ1auo0GGuUrbpQSdZtqHnJrT7JdMNgIhAOtQ4+Eaup7fsjEMJBb2zutlpKH8oNuYl6hcn0OzcM7L"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598442904.0_1598442913674_0.5827109720884718"},"_hasShrinkwrap":false},"1.5.1-canary.1598447580.0":{"name":"@joist/component","version":"1.5.1-canary.1598447580.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598447580.0+406e080"},"gitHead":"406e080386fffb30e115cd63c1c967b534396c8e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) \n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598447580.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-egPDzhweSkNzKp3kGRHetSSsWjbPceLv85YvgCO4pMW4cvWf5DD+Da+l52eykwCWIx7+bXo6Ke7PzF/eB3mvpA==","shasum":"21012a59931fc5f2fdecb6ec56a5ec6672461d47","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598447580.0.tgz","fileCount":31,"unpackedSize":39806,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfRl/mCRA9TVsSAnZWagAAtUoP/2peU9eJ++xGgxSf6QDu\ncp8kvwi/wjM/M+pmzV75RcZvYReWKAFz3O/we2UanrapiT0BoKP7QQojfZqv\n0+v/SYoxw7JFrqIofp5WUOek9MJeuc9nSQGUtTfcVl/qO/OpB4yVIL+g7CBW\nhLhQZi80hArOUFDJ2gGKD/jKpgksWBuiEg4fbV/Kx+AapfgYUiJcX0CHH86i\nZ0+qSTgwSucDRP9akpvI+BSy7g5SSlZEE59gVygOWKO9RKqloIaQrfIHzJjF\ncrgheatoW1b1LaMAPbB60aKf3lnu59IBYdjFAbV7vDvYW3HT4pXN/SzYWGS4\nrbTWTLazW0WVvI3ewvfbx+HFVCzprKnpreb4qbU0srOT4n/5DZD8AyvQVs9z\nxothO7jo/ZEj/KfdGz0Gn2L/hcxNngpk4V2aYmydzXKmcq6ZH9ziwHfStiG0\nkhSKH3clMaE7RRTNuHW0DW5AWuj9s4m27xGzHg99X6LDV3YaxmgGgcMs9IRS\nVYOVEQfZS9GsPAHRxBShoEiZNFV7XYu4lufMxkGsxjGnFE3doI6XXQZXKTE6\npAzQgfJHyBdHkoaUqh31esXecJRjU6ExDghrNuVedEMF/1BuSNH3AqcX7os0\nUkEiqKI7tO6n0b08Wxmv9BvA0By/jKpoM09BwXF9ImzMtFFn//jpGJH2VzEq\n00xn\r\n=hOnx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCj6HOBFBulK9CV5DVXNJLIpc53sL+Zhs35z7PvIAUoiQIgeC2Bq+wcusGCT/B/bToKGurNni3C+UWJo097yBYPg3M="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598447580.0_1598447590308_0.8309269784094662"},"_hasShrinkwrap":false},"1.5.1-canary.1598527037.0":{"name":"@joist/component","version":"1.5.1-canary.1598527037.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598527037.0+f95aab4"},"gitHead":"f95aab4619213d12f1b9efe2db8dd4adce151cf2","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) \n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598527037.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Jrp9Mp66SpDkezUeioQOKCBqVsUABLBcvANiJLApf1vhoASFQ+Zn8MJNEcw3fIVfoABY/gLxyQjF321d66RPFw==","shasum":"90de9f6bd04573c83c0abb307ff641b407869ce0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598527037.0.tgz","fileCount":31,"unpackedSize":39806,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfR5ZFCRA9TVsSAnZWagAAgjIP/jhz3Ap9aDUWNtXLr3mh\n3ySyHk/6ULimH5cCekaAHldvy3SrWqJapxOFXIaNZLTCRGHMaQ3OtnQO8MBb\n/U4yXD1zHlDnK2F0zluWM2Ve+sSepzNjHwmuvyXiYGAOxBsoBCeFQPSmWyLJ\nvyz7K7Gc/nWONk8GVlyYZgtkDOzBJOeepI5LdWQ/8a0W7+rVKN30lW4dHaWE\nn/mnvpJXQpujqUk7Ku0yuFn8LBCkE2CZqM+kKRP2R0/U4TRaDX7rWLBXZZfE\n3dcJ9Q+DGEEc9SWr9i38fGoZORjggzkPmhpoKtHHYA+14mICsT0ZC4zq2bUy\nde0gGRUzK856LoGFaxjHHqXLqnNZtiHLSuEcawNd1SLoZn67sfSJuMhfKwQU\nzQ/N6iNuwc8khR9cA1opIQX+vEWLwybKBXc0C1Uk2IFi293+e1MYkWZxD1rd\nwpIV6LSTiXimF12gGiASG5/oyU7FabjDJK8zNaqXOnABTCjqIlYzBMRDGv4J\nA5G3Veup478zbLSVHwoQSgfnjR20fQt6sRLZscF92IT4XAYTmE8WOwKBhUar\nV3VSBs04uU00P0mwHRsHjL5aSXUO1/DhjfkGtSMlCTDDS6tZFHa9acpt1L+p\n2fO/YFPLg0VuyIEWadjXi5wEUQRE3WXD96cYr+LEwaG0cv8u+ND04PZYAEk7\nxJlS\r\n=6XUI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBuPPd8Ka4DHjvj21jTDQGOIvGZ+0vRxeJNVzUc3RkLtAiEA/ZuInetnbylpU1Z9gRgXkmETa9DwqVz2Yh+nAr2YxD8="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598527037.0_1598527045505_0.6074405527199118"},"_hasShrinkwrap":false},"1.5.1-canary.1598527094.0":{"name":"@joist/component","version":"1.5.1-canary.1598527094.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598527094.0+8efbd2b"},"gitHead":"8efbd2ba8a370302d12c21f3dcf45316058c69a4","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) \n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598527094.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-vbqTHitNmlJUtNr/0QObXPrDoEEHl+6Rb2mkbQfaW87sJQO99Ia5gxHgsxBKpVQz0Jdp6H5hVMw9YbuRkg1J1w==","shasum":"9e7e94b25a2d31314c57104fc082b9871c4367c2","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598527094.0.tgz","fileCount":31,"unpackedSize":39806,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfR5aACRA9TVsSAnZWagAALcQP/3Ycjv2Q2nrBo3ecKghu\nzHQ1I1kHb6imViymuL6mbnuqmixO+WPhEnoak5Rq5U5FlM/35/wUFy7fdK3i\nD2I543YcpZ9wxZyAlFd44nYoYwAexckXACdDB4dAqoFZh/2/e17+s0dAaOLx\ndj3Kn/RSs2ItUaB/LzZDLVpty/YDS7hTO5iy/7Az5dnxrz6yVwKOiy3IAgQX\nH7hYHpcME4UnMy+XJeaKT2hKVexbHsO7pNMbgBA97AHJI9tuwhf0HDHyzQBr\nkZPnKmZqSzs59sUojBo2PzayDekBm+YMP9OzYIhbeWYx89qCgUaHbF4S2Wz2\nm/SwUEIR4fi3HxCzKRxLWbv4nCbsMYEqrCdX9Dd00TBI+/aAwokxElGJk6hZ\njvYaCRcwzGBBL6U/K10Y4o3orEqxi3SbNh6DGc9k0x8WXRxUjgQ4WFxEAY6I\njviFJh+kgqB+qQ7ytmyeBwRFKA+oyplxqPMBEhEz+B90oK9msnA9XYTEKCkk\nK+t53loIJ3w267Z5+JGEDBUh/pbSKnogH8Q+/Expj98IIC9IfiKEJmOHQk5U\nmML8xFY1G/ta33qhm2TuY57m/hHM3YyuRN0rrUF9c2QMs+rnMF7e+xLJcUhK\nGmXc77Nhb7Ky41vcgcYv9MHU1gI7KWSpA1t4ClWrZ9cLqeyCqkkwUMeuaSlQ\nXZjn\r\n=2HHu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC9D04mSGr3rHVIbbcFSMllmIWuqh3aQTE3rs3mAavw6QIgaQlnxT9svWYEx7xdSseUiukHj0EC/vPO4rILtLQYCxw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598527094.0_1598527103946_0.451827065464117"},"_hasShrinkwrap":false},"1.5.1-canary.1598527157.0":{"name":"@joist/component","version":"1.5.1-canary.1598527157.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598527157.0+fd371f8"},"gitHead":"fd371f8b55a5fea2c23139b1b293a720f4f945a1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) \n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598527157.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-dKYy3nSAkQNp3Gv1dVwq5YykcCLxu04z3y90iyVfW5OpQ1pbZPiW0wEZk9je7OgPHsBYKflU/16nHM+Zde85JQ==","shasum":"d0b990dfe6cd5629cd7554311260c80ff0f0846b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598527157.0.tgz","fileCount":31,"unpackedSize":39806,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfR5a9CRA9TVsSAnZWagAAwn8P/Rc81Sz3zGGpLa4sf83y\nVt6oSSFQib5M7ZiUzUuZGBfHduU1Ke45/xFwyF6qLVPGhFU7NVCi4gzS5sEX\nyKmKKoPGBBLabre3oRrG4mTeHT1LytfW6jylNpzVvgAN57WlfVTxiTvrPRfB\n9Q8ObT8XiRybZGADhvOl2iRUAjkbEkMJfS0lUP9IzWyJYzda3GGOzQyGOlGX\n2IYJcUFgB/0f/6R0qo7Kbb7+HqzTcTe27fy+x79Pcn+9vlM9le8/5ys/KBzc\nw4zC5qfE2zTLK87kHwvO/yogfrTfXhPi5NXbfhGaLl73TMUFZQonkc8MmUut\n57r5n5RKtE7iOUKmDScxI+7LdA2DCg1zHRfRdqzFnmvq/Blj0ICobkGTqWZM\n7BzgQaSnFErWQbAjD5SjLJnbnr5on+1Fcw4Fq1F99pRxmjcFYfrBMQ5vu9Ey\nudOHe/4dOfjFoKKKkifnlAs6bBN16pdaA2Qg0Use6G8Vlqn2CIlgRHy0oWMN\n8dVJ29e16WF4pfUZFrD2VOuCiZ8aKsEDUDnrE6Tmupsq+ngTJersuzS385O4\nyPevBi5KfQn2YNUrcQMDwB1qclqDdxYec8pZMB12Zn1ngnuo5mtSMnhQfK+/\nIxhKr4rgfh2MrE1rmqNasbQN1SYJWGdMW9fHbXZHjNYBtjGs8NKEQr4NW75W\nQeYz\r\n=BgFz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCGd8EdSr3PowmzofScph5MKERAwz7xJ4RcQ4C3VhnwbAIhAIL0M28hWVES+lTMQ1IrxRLUcqLtrp1d45btGVsUFeC7"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598527157.0_1598527164688_0.7684463813481295"},"_hasShrinkwrap":false},"1.5.1-canary.1598530503.0":{"name":"@joist/component","version":"1.5.1-canary.1598530503.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598530503.0+61d2484"},"gitHead":"61d24844d4660a41b2582101635cefdf89dd5d9e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) \n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598530503.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-eTNH3tu/wnDEVjSRiDHBaHDSa+dqkq2QPb3EOw/MXYBFtucv1HvxzwCNuaQnUDsS10kEtVdzV1yINIrEyLIXZg==","shasum":"85236c268aeb3c610324a9550031d184875941b8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598530503.0.tgz","fileCount":31,"unpackedSize":39806,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfR6PeCRA9TVsSAnZWagAA/EcP/1yocC3vOjYR8F9UYnto\nSybpjrJtO5BFVA+lIzaDZfm3CCKkRwckiSj+GdL3CTA4LuR+8MEAxQqXwBqr\nByGSa3oOEkjoLZH7Y81Pb1Y/rKGeaQNEPO0V5V0OZAU+KOKUEVpGrcy6wqSR\nfYCVv2fdNi+xLus4+wKvKfUn0Lut1LfHk0AYgeNy4clZJItiEVHwD8YpGoYC\n58/uSnPnFj+nbp5jWrT/s0V6Aq3/ur+KWXzrhx+oihopHBqi2GrmXUOL+PyY\nMoHvtavVpzVtvvpVgy7Gdbdf73RRDVKOir+7BBbWV26smG/DITg0GTIHbZlC\nvuJwdRff24pWMJZ2KCojp4Gkh2ZwrPMeai4J2rf442MT6Rq8A0y90DwsflTz\nKVJSITRUkcwh2FEogNX4ZMNiPCiv7u06PZ8AqL/pVGI5js7O3DXb+hvaJYKn\n+9ygbexSCazTNnKdrN/RHhaijrDxIQZqZTTT8jvNtRZi4e5f1CU72aLaDTvY\niZ3XzJyVm97X4klOVw2KicO90yqj79e064lbrv3y0RAjS7ibyWDsL3Al/ZW2\nXHUkpvw5TfrpsVFxGzQtV7Jh86ehL5LYCnVU3JfMpKLjL9OUhN7/ciA8YIPt\nW2moEwYaKiTNRZ6jp/Ba8o3f2OqBF6mZHYU/OCwQqHlA9vlP7AhxpTLNWFuU\nPrPs\r\n=l0lx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG7XdSfofAIhC0ep95dMRCXX0Cx1Bln4r4sxn+cqZK/8AiB/gxNgG18Ik/jXGkgKZYnjN+KBcUyXFvzRnEWw4Dc3UQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598530503.0_1598530519322_0.3400656180301944"},"_hasShrinkwrap":false},"1.5.1-canary.1598546041.0":{"name":"@joist/component","version":"1.5.1-canary.1598546041.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598546041.0+3e86a39"},"gitHead":"3e86a39f739339411776bce2a25f602a449fb43a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n  \n  @property()\n  public bar = '';\n  \n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/) \n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598546041.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-4YXXXVjvl0lmHIXbm9uWfK8ltY+9XnA8o8s5/KCYO3MmfTbHSFFq/Gi++sQaOqGDI+KX2mv/n3qaOFwBuCYoOw==","shasum":"efa6a6d901325f8760d88bd62fad10078db70b4d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598546041.0.tgz","fileCount":31,"unpackedSize":39806,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfR+CDCRA9TVsSAnZWagAAkYwP/0HWX+cRFgzvYDWfNwGJ\nhOeeHs7vdCdaxmtNPE03U9iUk7CUHtPtAWCqyi+4Dq+Z6cmLwmk1G3Q+aXSp\nx43vHZkNaupZmbPM8D+kztsg6AApKx1x0aUdAdv4ttKuqSunO8In9zPQiSH0\nb2SI1Od+PzAlEE7ny9DiOnbMYnCHzSkd3UzrKbPPyATTqYgsCDkdKSLRP4aU\np2MeZLdmiJ0DzfqbFtt/WhXWEFhJ5UHsdSAARvEm1NRrDx+R22VnMWXnsind\nGqUEDRjPU5uGqEhv9lkf78jhDggUHpYIsQkn5OHQEvntx2affCXIr+/sXfDr\nO0xg+M3tsd1RL23TYwZEYvoxPF2wfuTL4/dn/XEZTjdkGJGKJUSrkIotdYk0\ngEtsrFxEl3/sEjOgZFtKONg/BigG7JsI8diT80eKy0fxzOXmRxANWw+BYhcY\nl+Z3n+oq3bUPC3xRk571oamNN8dM931dn0uvtzWuVDXaQdJ0Y+qUsms30OiD\nIUfsVMFswMe6GhD2ufByp4hxuP2EbB+HCwGWABmoK7ETvZTSGQy6WyWym9oy\nvIFDtp5kotyBmFEQc43YUDaEvv104jae6OgcSWHXQQSx2p3V+IwjN/+2LlKT\nP2D+DtrCM1jORyH6Yy4Avsvgwxn1gsqZgrMq6DpbpE/TyKUNPBye41N739Ac\n8vZb\r\n=wlyh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCLk2/McTnf2QF1kLMbfxqm/9RcLxN94+KdFO3QF0O0CgIhAOwL/chRYsEbAsG3Z1RGyHvhr9hlhimYOPlEO9dFautL"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598546041.0_1598546050892_0.9171431576025666"},"_hasShrinkwrap":false},"1.5.1-canary.1598620401.0":{"name":"@joist/component","version":"1.5.1-canary.1598620401.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598620401.0+bf7f3dc"},"gitHead":"bf7f3dc849d1e65add66d002e3ec2d06e358eb78","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onHandersDone` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  either(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  @handle(/.*/)\n  onActionDispatched(e: Event, payload: any, name: string) {\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n\n  onHandlersDone(action: string, res: any[]) {\n    console.log(`${action} has been called and completed`);\n    console.log(`New state is ${this.state.value}`);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598620401.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-IKW5n4K+FPYO+FOB1xeNcSTUaPIlJFj17fGDT5dbcsO0LlX6H3WlldmDGg/tQtF+rHYryQj/uFu5cpq6B05aUQ==","shasum":"313a845fcc63b2d8a32f46f2ce9be196252565d0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598620401.0.tgz","fileCount":31,"unpackedSize":42098,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSQL8CRA9TVsSAnZWagAAFDMQAJ9qo8dhpL+/gh7pPJp3\nzuF96mtG8FijgeME6UKuPI86fjvXTQMeDzn07QC+md2w2tCUYzHKUCuyB3s8\nCeUOP6d28xIaMz1hojZVbhXfe4Lc3B6o5G9rYBYF0LlJXNEWZALzz/dXbRbQ\nYIdqW3R6pOT//ANxq01d6Kq/2K/EhT3841v3wOcyw4TfaVR02f7UMmHdXDH7\nD2iGeBf3LvpVVETvXtkNZ6Cp5aTXen/n6eUdt3CGKLLX6q1/nxNvIMvtL/aN\n25c2HX5BP74S+8SXMcpqBg1dC28hw9e7cETvFIQphBaNIViaTZscRwHOaWQk\n97wRII0EduPMz2OrQDhZP14tcMETR/TIzZPo912PtCVQUNBVBpFqWyQ85to4\nk1Q0VQhHR20K8o3ZW+I5srqoj+mfa1EwH2VCJmyndzA0xdi5IXfUbhxPiQiT\nuruthksn8F0BgLNo4aCS6QwMjR6ANwEWUP+/b86qFVMnBkzypGICGSy5FOUg\n/B4iO4/swEAnBs2w3iqoEySwIPNbNFedSfanAMjjpBjwYaWvxJI2ff+1RSAn\nHXcYEkhZk5sscYe628WfaFVly0TTwAK2iL9Vj4qL4NebRjbn+c/xPqAmOFlA\nmYUMsKgCbbalcrI0voWp0H71PZBvhlauJ/+nesAwJuXE2bgDFcG0hNEQp4n6\n9MTe\r\n=C7Ut\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA2tAxePPF+ZHxi76oQCz0mEuDzteu9BA/FSIuUKVWmMAiEAq+rriW5HHPwPh523YYzB5cfGsxOV5qThdPJ0+D4xei8="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598620401.0_1598620411503_0.1722885521678441"},"_hasShrinkwrap":false},"1.5.1-canary.1598628434.0":{"name":"@joist/component","version":"1.5.1-canary.1598628434.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598628434.0+b8b28f3"},"gitHead":"b8b28f323666c03edcb2a56dca78b9a0de359b22","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onHandersDone` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  either(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  @handle(/.*/)\n  onActionDispatched(e: Event, payload: any, name: string) {\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n\n  onHandlersDone(action: string, res: any[]) {\n    console.log(`${action} has been called and completed`);\n    console.log(`New state is ${this.state.value}`);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598628434.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-xHAT8ZekyhTuGlGCSjSh3Vob4sRhIpf5FBkWoklDhpPPZNfmGaaYP3PP4kYJXBYWRWyMuu+E0ZxMyeMGSCH9bg==","shasum":"18ba06ad1a26a4d9cebb9f399700451947bb1441","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598628434.0.tgz","fileCount":31,"unpackedSize":42098,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSSJdCRA9TVsSAnZWagAAsiUP/0LpGVaTMF6bpcMf5/79\nHged5ap9BsP3n85ghHRxs5HUdAzksRNDSvasgpmw5ZZbY6bKmV8NmMZw1ZP/\nDX91Wy7VzkcDcYLydWA4FMRQXQK6qKGt24ywKJ/pKbykCEaog+bvkWnZoa/E\nJODZUZTnO/9A92qimRYaux1JaErcg+z9sbFFS41OiD19scgN2IHmOirMB4/k\nj7pFW9la+aSvSM6FLwni3MDiH44KNAi5sK2H4YbxkbhWs9/hOjDgCgZ/d4Im\nlRjcuFfqjTF1Hh7QcjxlCXikMUWAk3QaX2HZ4fwjWwkaxRj15DdhF1ZnDhuI\nAchK2ZkURwpWGoZJzNPWW8hHOshuUHZar7fdiIe7lpqvVhLLyDv6sfQ4u2N/\nDmQmxzPVyQACzxwE7yuQNKjvQGsXhW4JNEqPNri6UvvwD58k199JamLDRZFf\nH0Znp4TVjr0vGBQqGjefTqCQzJJbvI6DRY3e25Jh0kXAcdfrbMfLZVv8r21f\nn+tViBGaxRtTpv8bl+yPPts/lB/A+sZzylKHYByHVDX+JBiHh7NmPaz8X29i\nK1sySxZse4LGdIU8/hv7cLt7GKBtoF3QrEV23aG6Qurh1mWdSz4ESPEAOEdd\nFbc9mDILlZ1Niwzj3YtqUme/qeXpTyEdlLxEITIAb6xKDm/dyXPsA5o0+NCX\nwdtD\r\n=rR2H\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDsJhOcQQEZQJOFVYU9I6E1ciG63ahD7izHHZj/NdSIZQIgRDR7JBO7PfTtuL/Hql9fnlzJtmjzbKVXVbiUHWPxbqI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598628434.0_1598628444707_0.11521342987132299"},"_hasShrinkwrap":false},"1.5.1-canary.1598629471.0":{"name":"@joist/component","version":"1.5.1-canary.1598629471.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.5.1-canary.1598629471.0+31b65a1"},"gitHead":"31b65a10f58bc0c97f28a9679c8069dbb65b1ba2","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  either(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  @handle(/.*/)\n  onActionDispatched(e: Event, payload: any, name: string) {\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log(`${action} has been called and completed`);\n    console.log(`New state is ${this.state.value}`);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.5.1-canary.1598629471.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-JI3Kd1nzXgqG8zbaHkHEF7cFRpjn5tdWcdtHpigh9nhs/CvaCgyDNwBxgCTUPdrGhiP4t6wcGnFqrp+sBewFag==","shasum":"9acab13bbe50a4752310442e14d44da97c65343f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.5.1-canary.1598629471.0.tgz","fileCount":31,"unpackedSize":42318,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSSZpCRA9TVsSAnZWagAA9VUP/ic49Pr+xLZxPlinOO4y\n9kxCvfnfPHjeekT4Qg1rRkfkkPQy1Q1Cu18I17cb4wGvb0GbaAfXQbOuKiGm\nFeUkf45IO9+0myK+lg5t15+FP4yzXI1W8W+UEXqQQ6/CdlYkm8zwvmKBD0Eb\nTVihnrgVdUGUHaHKlcTo9IadKLHpSe7Xq+xooqA/iRbQN4tXp4x3HjY4jc0R\nYMOz4YN3hdEGup9GzJwIWDEbtP4sFm2JmdQsCyzDNThM3lIgPKAI9muKHqml\nCXNQM52nUL8onAVpoM66lLd3lQkCD6vk5Q1VACU23Htkmzh8RiGLq3so5kUI\nnK7u2LCLbczk6Nz8dqab6YkqE7uSa5IsxPN0OuH8oILUli1xLqnJx4V0LFeW\n60qgCazd6uFMD9Ns2mMyf/ukisUqrE27bCZWlLa3fPPiQAcF/MaU0D0oxGHu\nV696EjUIvD21dwN8O6AsKzPk+DpgfZB3EJQjUBjAS7g6tP0AAJ9IVq0P0+CX\np+VRMpkfrkOXAidPSZ9W+uZ8HimzcaYqmyvSVhIlKQc4a7XNvlG/dXhMtlyy\nZDX8UzAH8AzttJvoY9Ab4jmmX/afBa7j8wyc8tQneUYlR/vZatZ5mXU8DMr1\nfhT7+Ck6/TXpAIjFOuZCYVkDXXxbRSBVuyGLEWUdjqj9hqnYe0jvo8a1Dlhk\n8szM\r\n=WbDp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC9dmlWY2y1L+4z4GbeiL18rZrwiftzPRZFdMQG7DgrtwIhAPEVRy4vRNORH7gRAfqJqBAPBrpYKiHCesZ8KyeA36dp"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.5.1-canary.1598629471.0_1598629480723_0.8347707036218954"},"_hasShrinkwrap":false},"1.6.0":{"name":"@joist/component","version":"1.6.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.0"},"gitHead":"c01a4133da0dc952983e75f3f395ec97c5430ab1","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.0","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-Y3Qi4jqpUnyELQNDUDec0nbR78O8l6iPuCzw+Uw8EPgtQT4DczegwT+RTE0EXeJB4YJeLcy3qCKHiBTqNanvdA==","shasum":"48db271e4d4283b6f4bac2015d7f5fe46bdd8e47","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.0.tgz","fileCount":31,"unpackedSize":42262,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSStQCRA9TVsSAnZWagAA7MkP/1YkT1c/Fy+xXY3UL7ji\nrkAkdK4BOq9eL+MyVN/Re/Bh3DMM+tajNtZrhI8MgRvVcCBd2Z7vi2sTv8Ap\n5hGWtwGz9JE53iPtEhrn7r85bFZlF98FKbaZXAP3CxMsXqJzVPgybD4ZbAvN\nWYoSDGp8qPpwE+yzbGYbNQg14GrB4maXN79LD1gvcRmj2h38Co5l1do3ne4v\ny9rONsoR186EqhascnsfZxpBxFCZ8+MKrf9/8FvNX3dzXAoinHzO6MeI/FEY\n+jXYZlP28DSyJWjZkX66+5dX8ccgtuWpBBmxmvirP/e+f6l9sl7I2V6O9ePO\nlJfGY/efO16AJt9fx6nMaQZ5lpR5na5o8/VmImY5J+lVSPi1R4DcXV/Bnrhr\nUYJYeodXkL5OZ9TuJPSc+gHR3hWLIM/KG82yZn0xZsTGjFGPpnCVZmLpsJ6T\n6g7ycKu+LomNKRgcNgkR1GOCdPl2IKd0tVTQ3qDJLQhmafDEN76Yny9dLlEZ\n4w045ugUy9duWeIZHk6vW2ZoxxjR/0L37OLRIM09Jq5nb99tq9mGNQuxBN78\nOPFthvSx3WhInMJIGK2W1pCYHkj0BPM5Isc3QiPas9227HHrBJhAfGfQyuGr\n+5HyyGZCnfYZw0vk6nCB3C0GSyQXDpS7eYgQQK57wJ2aldxvLZaZAJoMLTK4\n67kX\r\n=mg+n\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBhL+wDWapZc6+eYp5kHfegahiXKJ0wEmY7KB9rk1fcuAiBLnEqXaES8H8MljPpycWO0yAki21polrZIAj9qDXUtwQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.0_1598630736256_0.9899462809081454"},"_hasShrinkwrap":false},"1.6.1-canary.1598630769.0":{"name":"@joist/component","version":"1.6.1-canary.1598630769.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598630769.0+c01a413"},"gitHead":"c01a4133da0dc952983e75f3f395ec97c5430ab1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  either(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  @handle(/.*/)\n  onActionDispatched(e: Event, payload: any, name: string) {\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log(`${action} has been called and completed`);\n    console.log(`New state is ${this.state.value}`);\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598630769.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-eNj/MgZb9UMiCaUWvOQRZZmLQ+p07qi1WTB/Q3M79Xwo2vlH7X3AtiqPETPbK5SuT/8RhaogrP5oIE9z3l4QZA==","shasum":"b788bb353f44ef06fd22cfa4549159c530b4d897","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598630769.0.tgz","fileCount":31,"unpackedSize":42318,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSSt8CRA9TVsSAnZWagAABekQAIJ0L3W+ZuDvQgEb7e4N\nkFjdFHXhjxY62DPLb4SaGdG3VK1um6us3Fzr4rLGgOFDSY15XfW5HlaXO0Iz\ncXPKNn9mkLhzlpSOgYXU3rT/mSE8sznNAUr0/j6YuwnAvdrBixSf9E+C+Srs\nBcJzCTD+Swmn/APEPL20fX5v3vNS+nRKysoNEjCS6jT0WfvNB8hltAcD1P5n\nVhmFXd3B9xLQqZMeM+AB+tGN7Yvse42fR9fRIa2vlm09K6Bngj+xy3oF09v0\n9iOOnYXJnWVEXnN6/ISSfSJXxLAuMZA+WPzZVgJLGCK5bS6vizqvMbwwI6Fl\nmYMKT/WxY0hfropQPfppPgjf7azP61Njffz7nigHwyJLG03y4oP2yRwQFUw9\n4duTfqhV99BomFxTwMnUOCZnU0HW5cSunrMM0XYVIOje3MXvdxFbYTY7kIeW\no+70Hhg9DKnAsYQ4peodCZMrFLC85/np6GBNjf5roHwXBqTNiMD3G7g/7tgn\nRrC5NxMytgXf6woPk7riuUsQldbd0fZgRK+ZvWxhiP+zQ7KAskNLb05gu1tI\nvKk6SMpHRFhKsSHSsGW3w5yxInlKsyDErnghDJsWy+7hKNhjD8j1zm7tulLo\nQ7qiaQkaFhtc/iiS2EC5QMPD5juBhoqjFgsPkWama/vrlTzi22IFKbPi9uAc\nunEf\r\n=GuQk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBFnqIh4ROpA2rbJiSvi1lFCj9Eb0nGA0vykMEWEiV8EAiADis5RgedMde3GsjMkiAQatll5ahX1X3Hjwx9WIH50eg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598630769.0_1598630780308_0.5211622005468792"},"_hasShrinkwrap":false},"1.6.1-canary.1598636182.0":{"name":"@joist/component","version":"1.6.1-canary.1598636182.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598636182.0+6c4c759"},"gitHead":"6c4c759f775cff6b483cb7e8ed0eb7defbaeacb2","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  either(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598636182.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-3Cl6DuI2pLDxbSWRwCHC7pxRaz2BxP5EmCFDYOplvSdb7c6MKkIY1xZq76C/3nNFlnWLzzvZrkA714GmoIfe3Q==","shasum":"7c3c18ac7e628d3957c3904641de7660b99cbd9d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598636182.0.tgz","fileCount":31,"unpackedSize":42072,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSUCfCRA9TVsSAnZWagAAbpAP/1ccfTojsPqGq6gC48OH\nzh/sNJ9Hl6Ksh269e3WCevkK8NP08kT5XQxyZgkDD9+/8lRNJD59DVimJno/\nAJsAVb/0h4RwZo1W4itYyZ0caTHEhc6xozzY+t8No8fhTJjle/1vXnosP1Z3\nHvBscZAhoJKGiN5axKJ6IFtee94jDmXDZhZ0p9cEE/qmURutiwjEed0QTp2V\nSercmhPKm8hVSdofoD5o5SChaTX5mKX4LNxMnoY6D5Bx2M3TgkG+4saIyOl5\nzcwr2q/FJ9wO/KQfChew/GWlPNycpm0i3F95Z5IxiiG7Jd+xkoY07/CA2Xql\nXVnWqDGkc5+KzXO3TFw1UmWjqdFQ+Rh8PJKdzE3C8W56GViM8IHkOnqD8uwc\nLgdX5H9Fc6ZUNS92ucQecNYT7YETECU5H8u2ClJUxIpR0/jomqbydnHHH6uN\nfCdbxS6DFsJji4ATbFaFY/OUiu53VmNZ30BkefRXd6C/IWEP+svR+HhNCgLu\nDVSSOVaLTfrz1m66/WzgUIhKTg45FVg3XbR4zIJUZYODmv4c1INTdEw/2HaR\n+tu7GGV1Qrw5x9F3nwBfYKDvHXF7WjMPD1Ee7zBuboaio1ojr5yibNFX6F0p\nWj2r0BveGu6UWrwDYmaOG3MJSkPDloEAOKNGWPHgUZNdlCpHTg9RX+vn4p5t\nWwr5\r\n=VfT3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCJ3Z1T08VnAIz2MotdQXC2VMV3dE8sl0UsbiUH0uquVgIhAPnTMfsBMGnqRk0jvmIljZ//SodWrPVp8cNchGxEszds"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598636182.0_1598636191507_0.19757653711453238"},"_hasShrinkwrap":false},"1.6.1-canary.1598636291.0":{"name":"@joist/component","version":"1.6.1-canary.1598636291.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598636291.0+9df8c8f"},"gitHead":"9df8c8ffd4b4786cf212556829ab06307fc56cd3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598636291.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-3V5LYHGgUVxn+NrGIa59pXqlEytg1Nm9w5Gt1gM/7vXqK4LDJuON3LQMkJl5JWdYxyAwOB6X7mvpJhy4E4pdnw==","shasum":"3c98bc80fe3f616d957e7f0d5b579e1cc855059a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598636291.0.tgz","fileCount":31,"unpackedSize":42077,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSUEMCRA9TVsSAnZWagAAWa0P/RJ+mponpQskZItfB/Wo\nBjLMpUtaNn9gh9mdPQKcKq/WRAaa2b1IQsChFXbcuvig8p055n94EB6dTkB1\nA+Zc5A1HfAYYCFm4vajrzjjFkklPX3djRhq2tIonAIe4hWd0FozuzjzB0ZJl\nqe4OJKf2FBYVuzFvqfFy/xH4Wa3fonYQxdwOVML1aIpvUDILAyPxQeyRqR3h\n59su7MaL5Au+WCsem9VX9+k9Rn456lcQlWD/1OcWv1Ukghmrfl69+MmPFtqH\nNPQ00YeMZ/BZbfs3/62+YKDFEsAqYgZI+qvd3lCHd9tUGjSQA5J+SVPdr1pC\nZcTTZZwtHoBzcgILpb8XL/8PoSN+ZGlDaMIJkV98XI12NPi2+vrwIGUb10dh\nPliRL8xj78haGRmrNkq3ZBhbhrsCxLWg7hYw+bax8zMzVGB4aBf0AiMxUWnD\ntyVGqENtVVcCsWA8qoYKfxQEsoadc7QS1dWIZcaGTe5Cqqu/Zxu5Jve75Hwx\nkl9hCAvwxFuXqSMZ9V7weSsCp1+JfhpInKXaWaXjLdvj4sdVFKo7hf/Cn1ZS\nye8QRfXMP7lStmJHoqnmkPR50kfv9DPrZFztz4bZdU6jkwmvAD5aQJydH3Zu\nM/bQZLHB43BRaPKee6tupDuHn9NM78QT0iQAmPxZx/3+E7e8aGc3LIAtZQad\n6qKZ\r\n=1Bc5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDF40sN9Hv4moyv109hFEuUnZBhevgzGfhrhU6BkG7zyQIgGXFgfUl0Qr64Z0gbPFFfTDhkWBU7l3ADIkM+iDHLk3U="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598636291.0_1598636300460_0.8950948874316835"},"_hasShrinkwrap":false},"1.6.1-canary.1598636394.0":{"name":"@joist/component","version":"1.6.1-canary.1598636394.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598636394.0+064bbb5"},"gitHead":"064bbb5e0c750cb6c0b47943708949dae279c1f4","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598636394.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-h+fzfNKh2P9s+4XylwjCCz837/Z8Z9KBilbHYHlSKHvy6VwQhed9mk9CLmhOiaMRmcjWHmv3OQKSvvz4VZC/dw==","shasum":"5f102f9aaaec4fde202ea160eafcc03abe8d22d4","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598636394.0.tgz","fileCount":31,"unpackedSize":42069,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSUF0CRA9TVsSAnZWagAA0+wP/j9oqW8876yWlD/pDx0P\nrq1NyJprFwH5zp3Jq9l/Ul9PgSFYeH8CFVrAlJr+tLoxF9IOP3ST4wFsJzJ+\nLMHr+Y2gIxFp15fiAfudUYmswASY0fjd2xkFQeISg1TveW8sip1YLT8xkMjr\nfnIQX1zNYPHLmZVop/7If70SY0gFZ1npuJd50oKVXRyhNIfETSnJfJzssvBk\nXF6o+hCGSBbfsJuCZNsTxc31lPxELUcKci83fAPVZ8pruylSaXYe/EApkQ+t\nsKTz+FiRgGzP9MDIcpl02wvY6rt5+GvbFqgGSvU0L/HBMsyStP5Lh6NkZfdv\nuQdEr0/gX101haxYENWmYGmbo3spzvXVMsv8IfEM72DqD2avOD2l+OIWlT00\nshSK/0dTFdFF+o2+RkTAtWBPY4WXY5kBP74rEbkIHV7lAR2W2ebenABcINMt\n5+9tKdHoZ+3KKGz2/QczJ2osEUaKBXeXj9fXXOGwZLSgrD74FJHMejO3JOLh\nxKEL3VYOapVTzssdFwwH5zyNndaHKpO9KSRRGgT8Jw0rmJGnzOdh00Mm8uL/\nuG0LVKZRJlgjFdqoLNa9FdXxnOCu8wGkOsjeF0M2SrdkMFSXLJChuUC5H+/X\n3jeenApmkGybLwKXM6TjbY07IznrFzm7etQhF3bHW69KWSaKvE//pU8ns0qL\nH/wk\r\n=nMD6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCCYjouFlltG+sJG0WEY9k3Azbvj/KopUZCkcS6Xfa3RAIgT6W2gzRxlwocidDzuZTy8KO2KQBOC/EewvPhrAKpc+I="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598636394.0_1598636403839_0.6408049681079593"},"_hasShrinkwrap":false},"1.6.1-canary.1598700250.0":{"name":"@joist/component","version":"1.6.1-canary.1598700250.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598700250.0+9925276"},"gitHead":"992527643251f18d6f46801965799278b9140027","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598700250.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-WstxMzqc5du53fNYKyRDin6L6RyyEu9HPkWIc3wJnedRJ/piK731m5wV/F8UyEOmzI6R2NLBSwj8USe77JOSAA==","shasum":"62a29b1c4144601b540d81e3fa705857e407b721","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598700250.0.tgz","fileCount":31,"unpackedSize":42069,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSjrkCRA9TVsSAnZWagAA19sP/2ImBYrxMcJtwJ6mNlMj\nmTh1BOzCHdsm1pq3JswgrA/yy2s9ODgJsdig5blfT1surkFFMYbrhra4w2um\npQv38uGfp8ydObaWlvYu2KORNyCHItazZPd9J4Z2xqdSa68W2Hn29BwBCpQx\njV7QqMuVkYw/9ECB22XCOXAhsawpArXDHQ1ypn3m7wSz7fo+E5Ls3RLKQ8yv\nIr78XDEoXWzD/wvzlD2t1NI15ia722KFNISI1DXDHsVoW/VKscuWI13q1gaS\nbI0ow+CoIdNZVHktfnrkOKHi/2osYV7VKV4gL58vDZNAOQ6GHsvcmgD1ZSUP\n8s4jUA5IO5IZ9SAkHIIs8LTMv2FAxVYsNxSjGoYI6oJzKPnKbMD+sJ4eXGPd\nkIGyVxg0KhL7P8sgBdumjD22iHULrJWnbf8ovN/TFq6Ng+tvB/ex4/lUz+Sm\nnzSdR91dh1YOGYj3PBj/4UJcCW5BQE0+45NEkQ82Fjdi02La2WGiB/bGxtI7\nPSQUtyFbQTmjYOwBiEGAMrVWwf4OstiEzDF4wqI+RHIypTJhF7spXYlpL4k/\n3vtgqJXTO9MHg5rl2+YHFQz8qnt5dn3UpEej3KKBig/HBTCPGRRtCU3BB5pb\nnCHv1ZoKU9cxplb97NRgagrjJNXiuBqXf+fjqhFKnuyHJDdZEHbLNmapdxba\nP32s\r\n=P2wf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCR3eHrgq+od1RqLmbba1tAWJ7ORBL2j6wUi4eISitjFQIgfPVE0m44jha2PCTrBh137WQNDzenkVsIVAqfX6udHC8="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598700250.0_1598700260155_0.3010520724737531"},"_hasShrinkwrap":false},"1.6.1-canary.1598734916.0":{"name":"@joist/component","version":"1.6.1-canary.1598734916.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598734916.0+b273893"},"gitHead":"b273893758cee157874e50c85e812ea19c29de97","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598734916.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-LYKyLhCIIJla55Fk19pbIZ/1+0CKMQKy9C4BrQI9WklkT1wSy6zhr+TO1r7qlIf57ktwnBswvuhWDJpGAFg40Q==","shasum":"756788f2b27b712f31aab7fb1064f35db96b2c65","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598734916.0.tgz","fileCount":31,"unpackedSize":42119,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSsJPCRA9TVsSAnZWagAAm0EP/27z5hzlRmllG63/Ktzl\njoieDU7uUlq6YuX6X2MWDWFntSC5rlFXIoU7bP7wlCgcbV8q7eLcJ9EWeDVj\naVsdL9u54/GfCROF41RbMJg03FDWWgCBzeBnG1DM/SPd9lJZBpZ0jeNWnobT\nOdceaO6Wy89CnI4XtyUTkmtBZVc/uInCqaB9gEJoq+mI/0CDfguEpRr1KeXI\nzcekvHRKOH2Jqv8Vx7zLWTLFGSUkgxU8B5MoFfaCyu8HtQJDEZZ28ffAYwEa\nNRYrEjjPorvnRv1xaaLThOA6wsUtpPiNDDHZVIxcrl0YRoYcKiQKFhAJuXCD\nqBDX2mY/vadkmOuT5s4QWX/gNAWAXgFoaU9ieWeSvqM5d3hkkHDPo/Ycd/iA\nneImmNpjETltK4BavHMO2QMepEs6GBNUDzpsrJDbGPVpSDLO+wBgl6/xE+lB\nPNKO9yt+pzhBwejphJ0DxlcE+/zB69t9+KS9QJdL+vBUpwZkJcJLq9pWtyC8\nb5CQkaNhwW9AJwHEO/mF1sH70Lsy1h3HN4mZ1LE0snusrrNHZFR3N8Fvt+kz\nSxqaLV+uPONUZ1wUYcDt/cdC43N1avPM9Np6mSg9luSNvSn035yV87fCRJfR\nS4adZ/vh7ME36GHKRXlRI/RCsYSiSUhpoTF09OrO4yNsbX0mnDFx7hMZkJ8A\ny9Lt\r\n=lAwi\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAjZQhXI5GenTregUJ0qw7kj/eCkDon86YNwzUKNC5lMAiEAgkwEg1P7//S1bU5N74vl2z75zW+wGCd5Is7GDFnyEZg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598734916.0_1598734926999_0.5539079414667993"},"_hasShrinkwrap":false},"1.6.1-canary.1598735539.0":{"name":"@joist/component","version":"1.6.1-canary.1598735539.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598735539.0+82fb574"},"gitHead":"82fb57498c951d5e45f9897d8a13fccc058a5ebd","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598735539.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-PH4Q7x9DeXInJmjiVCtpjnrjaoaZRPGAXXQJYx/vPu2IyKJTuF3lZtLJTJyIyPkkoq+ftRNkGwMyBh9XXNgDnQ==","shasum":"4b39830f6695041378f4c8b338560666654b2f41","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598735539.0.tgz","fileCount":31,"unpackedSize":42140,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSsS7CRA9TVsSAnZWagAAK4oP/2vE7L+EJXC6S9qUQsN3\n94vCvNH2+BHUwNo1pR1cj7zEjof40spNSMGxl1dPcqvkOQPfZQqhQ9EacgvE\nfTZJiszsMzF9gOCAexb6jx5OXxiQWr4UBXZKH1vjrsOcRa5WnuBsCU0ClMEk\nLwHCy+/z6YEeQIz5V2hZ33SAeUG6ZaW3oA9QWyCSqdoJXWb3ADSDppSWUKu/\n31Q24ftyLsqAQcNGPwJRZdWV5wMREKVU7gKOsMdZtS1R7rFdnp3hyE0/QTkr\nfnnXqtHZMIBnmfCMbA8NYCcTBfHySU+0KXCt+OjxAjwAN/j2kc4doyRI91OV\nD6odm3by1X6MY3mKklHTW8aspvQ43X+otNLhWyg4AW9rP+L8NSe76F9i8Iar\nZC3lSXJsuaT9DW0/pHrPaM2qitcVEqMFnZmDa9oG3yGt36cKute89ynDb2TH\ndvJJ+nyAtFljskzidPvtgStHURTiIn4D5ogzwlL+s0Kq3U4UC0RyHas3dXhz\nalKejfbC46ciz0Pi5InkCwKd0suMgRZEd3WRUs/5o2uElBRXnuPALvbOViyc\npuovGflSit/sUPFpfIbln7/m365n0JvMtAgbS2ecVuhFce/xacBPtSIbo4i8\nAn7s3q22MtMriSGW5OvADccto9UhykP9wIwiqPEEFtXqE1jNfS0aVzsG8Zf8\nkhMc\r\n=Oddp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCz9rsfSE237ekrHZ0A72O3IMmuyYew+E9JYw0tqcliVQIgXl0X9jZvgW2ISS0XYfVqREb1VGxXt/iwNqq5t7Pznuo="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598735539.0_1598735547440_0.5187798595632509"},"_hasShrinkwrap":false},"1.6.1-canary.1598744040.0":{"name":"@joist/component","version":"1.6.1-canary.1598744040.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598744040.0+d54413f"},"gitHead":"d54413f523566a00140b4ed4ed145d3580f756bc","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598744040.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-NyzUKNR1QUMOiidrN0eS94GJyB7DfKQTSJhMgq8/qgpBDWHusf9kX2r3ikfei0SDxFQzcxgRuFE1I0CbXLwrOw==","shasum":"f51bc5a18d641a14a3981a709981efb1430ca976","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598744040.0.tgz","fileCount":31,"unpackedSize":42167,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfSuXyCRA9TVsSAnZWagAAFt0P+gNDovRvysObH61uhDnM\nhQP4McRLmCBM0CQ/pY+BPpLGyGMzhyQx2zPdkl2vYWevU2atbC3HSFISszip\nJd6fPyIkpoygbbXe6Y2Sck1/yddGTqZws9dZ19Idg7jZsxwzNKlbzXyKybnk\nUlfE1DhowC/cS56OpJfOY1C/gm/iYKj9ZTNdMvvv7IU6oADnGf8KZ9OqpPi4\n/rqvzbs6fnzNiceZcZ8IfmBHrqF5WzqfDV6iQoSXm+D0pkWQIu2D4Y4SKIqz\nmfPLxYPsHt+yLQvIgKZG1tzbNBrSDJrixuh7UX/paslIwX/8ffYsFCVGsG3J\njIioPb3V3SBf2eLu43sI9D5hFNyxAHug7ldXdnVpMTHECg1Nd5O1aAX0eplw\n/WAohVFZr6PAK1DVHIvdHDadBg9EuUlRxuG2qV71odZN6GwMXr7jWnlUbSSX\njWsbSYugN26dJ5Jp240p6s0oAg0HeojEvIVkYUqCl2hxMYk/EW9mFsTabUW5\nnp1O93RYb0ITCI8VDYrPIRZJXc9EXwp7kkQ/hqg8IpmNZ3o/p6R/cdWbCyTi\nZxmFLQKWRKwnTxN+xCgd5tA/AfH4fJ0tojebQweyC7p9KHaAzS1bcJqMagJM\noStrCQKtd1hZAg/AsKVjhVRZga6fbEb+AjeuaBvahFr7lCuk78nxHyipf8fi\nbNub\r\n=Qwnz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDIR8dJUCh4+VNHncbs1rs4U5oAp8XYMxN6iQJWMopooAiEAlqcE6tqGksl12kP3brMQyvXr4lfMKiux481rA9PgJ+k="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598744040.0_1598744049601_0.3862518311556482"},"_hasShrinkwrap":false},"1.6.1-canary.1598794783.0":{"name":"@joist/component","version":"1.6.1-canary.1598794783.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598794783.0+c6ddc4a"},"gitHead":"c6ddc4aea78b1fff9a8c9ec277659483dbab1e4c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598794783.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-oia3kbyuQWsBo1z380IWpe11NI+DYdQ/BFgRjuSezO8BQzD7BWU9CMOepcHZJOWcXG4W/+KYd2nR+VAZqcgb+w==","shasum":"3e5a184a96fd5ff7b1034331b05a75ff438ca8a7","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598794783.0.tgz","fileCount":31,"unpackedSize":42167,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfS6wpCRA9TVsSAnZWagAAJ3cP/1WOj8e4ZjlVvmdDtrQD\nMaD3CgJupShQ0vFgkHOOLHiIGP2frhoakoiUCtyQ5fo5GzK2Gkmkw0oL5EoP\n4aPisPSTcomxdeMdNApZeBWxVQUFK2angZb5fcnbGjAjrmMqSPQJlcglwHnq\nO+ofcEZOu2TdK6Ac0Eq2x74M8LeqS4OgkrSx/8INUIOl551XUy+3IpogmLI+\nPxKQEeHdGaWZA2B5hAB4VFxn1NTiTReZ066u95I9KHJyvBRarcz34FC05HDW\n5HPhx4DiIIi5MkRRFwnP7OFieGLNfKYOSzt1dsEOb2H3n/aAvUuxCSiwwv2D\n4K9X6M38QBjGVQJX7co4Bwkgv3wqXGCaHZDlblA5HRJ8cKaw/lggrH3PSv3H\nZ1Ju5FI1hnQwW+Ai7BMYkzCs+SBWEUP1NjGTdvvxM9W8jTEHFexCx8tv+y8y\nIz2id20p38xuVaCgM6d5mBv2cADnbPrNc7eBtfEOWfixH+HwtuIxrrJFffzE\nc198GZuNv0XyIZDcsuQdRZGs7bbo5EpxeQpXH3p/vn6B4HOh90eOz5xIB7mj\nEuKHd/WjZO1vyNnQuAxymMH+eq3JAsYutDRTfG2S6qryrPXf2ZUp7sog1Auj\n4K6uQjIYZGZl+S61x8362nFRG/ojMhLGku2xugNbWfdH5dgogFwxFuqDF3sw\naqGf\r\n=aES4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICW27vmqOYU51PphzvWl0PvJcCdLsIYxxr7PpmukhVxrAiEA4331rwUbrR/Kwblz4PPNhIv4sPXSQ8Pqt+c+ZGTgRaA="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598794783.0_1598794792897_0.30306769550680235"},"_hasShrinkwrap":false},"1.6.1-canary.1598798708.0":{"name":"@joist/component","version":"1.6.1-canary.1598798708.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598798708.0+83c7397"},"gitHead":"83c73975a8342a6fcc5112182fb9c3cd3775f77d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598798708.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-cJ/Tu0UGsqdZwzOTkVYaBcxWqJim7K9bsDjuxqDR/MEJAFKF+u0tgi/nmN800cDiiMXxjV4rFrie6+tu6LeK8w==","shasum":"9883ec6528d88134a842cd65a332d335f849b9d2","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598798708.0.tgz","fileCount":31,"unpackedSize":42167,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfS7t/CRA9TVsSAnZWagAA1fkP/3XgzOipkt5lERKRlwZ7\nY3Qn/9C86TBirmpX4KSwbrV/nRud8+1t46ceS3v/goT9C9ffNP4v89BAtScI\n4rgZ7eKhbBSMx1Hsi1rX6evqs1vrD0W5GT01jUFPdqVsX6zhiW/3pSLRYTfS\nYhD3hMHabTtfrj5BsnNw117B1tC6ECL5k16RlYFVXbKkD4GKphLoSW16/JDE\nnv2/pjOvbWTXNJ16a/wetCnj9T3AWAFAGtHNfIqdavi/TmGkOUqLJKe4uUJA\nqVpjgAuf/uVHmVMlC91CfI4r9J9YypUUwzXpB1BIcxyRdFMDxUS/o8dlnJIz\nh9/sQSgS42XkrCjKEB4BSxdp2HjzISyyH2bSP8y3gUwg7AwpMaVKXls6zssp\noR8dLV53XlIkvq0xUJMONH5YtWMyj2jL7nKv3hKw9fxjTlpKisdJLdMIezeS\nU+eTy6K9HgUGBh0xYKzslgckyT/Fzu4eWGkdet9iQCK2QOZAKa98O1FKconl\nSJUR9C2nX8vGYl9uPnblZ//RUNFa57b/MUQJS4XwfCDX5/07gqRZlvpeTaap\nFKLV8ZvM7kDLYWCh5kQZHRv+RqwAha5sjK/+S702MtMi8bdUFy9ARHeUCqOw\n6flcw/UzyQJMhAoeZEtc6lne+HJfytCNi6b1B0+a9VoZyT++zEetLEPjs40D\n3L9v\r\n=FoWt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH0a7ZKJVAggZ022vqQlMvaSkWiyEUPJIHf0LFG2kQmbAiBcQZm5Kqrte1tEEGZ1UWRN3xTHxAOMB6U6eukh+NXhqA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598798708.0_1598798718606_0.34176230902103"},"_hasShrinkwrap":false},"1.6.1-canary.1598900228.0":{"name":"@joist/component","version":"1.6.1-canary.1598900228.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598900228.0+085dd0c"},"gitHead":"085dd0c6d62799b32e9a7564a78446dc6c6342f5","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598900228.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-7U21pM8oZXu4L0IdADydRHwUxg8kOWo/1D0BTuSgwM5DvdzkERZC8tP6JLYBy4iVQ0uJj0DbbpYzsdy9sAhcww==","shasum":"a5b1de75d86cad7630dfb581c72b46d0975407bd","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598900228.0.tgz","fileCount":31,"unpackedSize":42473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTUgOCRA9TVsSAnZWagAAKHUP/iukLfGBzDapy5EpF38U\nsT3VqiRXU636/nRDsBOBPizMIy60m5NxJ6C1HFEV6CnssIpzJPhnq4fu9YSM\nfubmPnWouygBS5moWrc43Fv4Pi6l1xQJJXktMwRo/PdIvDTvwsW5qQCoq3pv\n5ghBu5dR+OdvBMugt4SS9OQHHK5c3ikfQ47N9RSTpPu1XBzo7dRJlVlx9XAZ\nixIgEpfGrchQwo3MeoIbeF55HB/Qo8PAQyK2szRcPRp/FpbvKNNdGLKM3Fj9\npEhPNaSoQi8ttcdhE2485hls/j6mj4Lv5JOQO+kcAarDdXWJcBvn867muF6D\nLcCMv/+zh2LpLWfjbusoJbthtr+dAcZjircfyqnlVTX1TEa9MgqN8ASszUO+\nbl/pCJMgNZ08qXympFQS8C1aGTEyrQD9Gu/naOSTqQmrh4r07dN6+67mBsdz\n5i7rXVllxXqXOhLm+TYptBfkVrLiJ3XYv1ojkVx9zF9seSvcsm4hyr4Mgz6u\nKRym2vWxVuBMx9Dw4m0LyTQ45/VZ2xWZvz9cOLq8Gq4DCMtKsQPHLcqLr/zX\npP8ZwlxktUBeyWJn7jZ9ummYqtYABkRZmUAkc/yEtDven5rXh/GlyEFZ1lR4\nt9BwUh0klLlqbfqqGkI1V+Yd49lFJHUlVZj1l2/JP/rYZEPrRLL/1zlwFxbj\nXB1C\r\n=i3Kl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDbjDcC5Mvun2A//yJJAmrj/+MmVe/WbDBkRyzYbpDYYAIhAPdOEf+LsJ6+3vRrbg5/KMY7l7BDtHBqIEHEEPJCaXkK"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598900228.0_1598900237821_0.9525628889360298"},"_hasShrinkwrap":false},"1.6.1-canary.1598904195.0":{"name":"@joist/component","version":"1.6.1-canary.1598904195.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598904195.0+5c2e72f"},"gitHead":"5c2e72f58ec22c04ff64c6432e79803baaf0781f","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598904195.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-t7koCAbJW0mEP2GAk4nPnvosgyfI4FW6K/e30MI5ek1xeX591AbJnaVaUd+S8uqmwFqW1fKuOBGTENyiXkVHbw==","shasum":"c91553cefd068d99e4bcdd2b6b02bf9ee59d8e65","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598904195.0.tgz","fileCount":31,"unpackedSize":42473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTVeMCRA9TVsSAnZWagAAKDEQAINjKZm7nGopwf0IH+TT\nXKNtru5rUTDqMlR7t+7HLY1NDKhPs1q2sP1Nfj2+QsT8k++XNpAcv06QP6/u\n7lKLJZImI4aRfMXM0HMmHfkB20bcDx9N3qJKNQRKgrYjD8WLFL3Tndp6FEPx\nbuEtQEt/aMyUWygGpn8JRHyXlA147pMudyNXmUoFlkYbbI1rB9vPNdL8gl3o\nMcEyCYksOMb1VW7UzIHhC0joG7qdiocss9nbFGXVJuuAlb4wIVMVYnAKLnQ3\n0cBXmTHzDd1jAe8IJmiWkyY6wwpQPZIfHZJKDsqm6qHj0qBallJSyat4MPrD\nsCvBuBwgjebnBXw42MuxcDd9j1iY7lM1LJm6KUu65/gxyuaii7xcOwBmN259\nKziO9CHWmR6llHsTnW7rTtMQWwtF5hMmictXZF7k6IRfeMRoFveNokgw8JKZ\n9R8aqDHsh8mac60vgIW7A2BSBjV1sZ2zw1Oy+zZjpjI3BqXOmjiEbrA3JQZF\nP5kM0IJuor666IF2c30+LatczdU671pYXe3qpCGQGd92YpXBHGnTB6OOeDhT\nHSiC37tVF0JlsZtTnzZDXfVasp2gM2VbzfWy3Tfp58QGvNaZduaA86G3VdsU\nWnuqC+Aym9F13EGfkoTbnfIYGld7q2O5pIsHi1foeIObvmVhYBJr0BHue7Xr\nbF8W\r\n=0qz2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDKxGZeKiQTshSluTRbF/g0aP+SiunayOu59t6aF32M/QIhAKie21wgR0vRZQTfrwsLQ7RbeyL57Yu08ljwnTqIip2K"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598904195.0_1598904204143_0.056528128785174436"},"_hasShrinkwrap":false},"1.6.1-canary.1598920916.0":{"name":"@joist/component","version":"1.6.1-canary.1598920916.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598920916.0+f5acb18"},"gitHead":"f5acb18c80a6731ec915388477792710d7b0956f","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598920916.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-2itF7K5FoFzVSpJ3QCE5bErzHMZVJ19wg8Za7aBbG3JvuqVVh7vTWP393kb7At9FPSuoBYxObTzkxiPeqMLDRw==","shasum":"4678e0a1e36f7c57bfc8de9e66295689db291c67","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598920916.0.tgz","fileCount":31,"unpackedSize":42473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTZjeCRA9TVsSAnZWagAAWDUP/iqYMfXmn/+3nQcPDUIN\nE1sNPd56ZGiJdF0LVUMPeJCjCgdEaQFIzIvrcZjezmR43HHDLG2wS0y2Sha8\nRLlpnmMWx6DwESGzrIx2m1ENqeza3CXUkbn6owoOb4wsmnYoMMvy7ldLnqY7\nVuAWT2cwBwHslKV0HlL9switB5rq84IyznTrGPInz/w8ViiFU63AX1XODe19\nNASg8A23E/KC7/wnNWsOydcV1cacan2Yi6srNq5lLx0dzeYThYvbMcXf85Gh\nvyy0pV8e93Td0rylAXvlsTBM7v4GUrrDFfH5p95fT+syWTdlsYMsuRyKgJWg\n3uP15UbWftJ1T7PR+OFT/GpHPCHhRSXwZk0ACDGHJiyYmXMfraEEybJACA8t\nLxGFAEsuuz6YVhau52+FyepywNYIuw4v7vmxo6g7ugJibI+XpXE5kmT8Q847\nufqUL2EGvVkIlaMP9f8VY2wQekSj02Z4s7qJmM3Sd7Y+yxOSU8OjrFlxtREG\nPHUplHRDcfnaa9uJb9IpPVCAOivC9k3yS+mRMxpAWZ66TV9kvpPtJdKdgYWq\n+Pib/HIGwdy8iGWJlVeMxCuLbT+a89tRSWayzLhwA+0bFrbaewa9Ra8PT2GK\nSg5aM2Zurm6crUcQhoFBmgViS/SA2k5IER/KdJO6avP2bKXhrF7w/4XbdK7g\n+CpJ\r\n=FmyM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCo99Ryi6iriGsrcHgeta56poJSxOvorPM3g7KlMjsFjwIhAPp/H70n3A1CLiS7wNofyE69MprB747ZWFd1bIld6xtt"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598920916.0_1598920925973_0.44845548185670725"},"_hasShrinkwrap":false},"1.6.1-canary.1598960325.0":{"name":"@joist/component","version":"1.6.1-canary.1598960325.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598960325.0+63af56d"},"gitHead":"63af56db6f096546255cfce4f386059acba4f519","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n\n      ${state}\n\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598960325.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-laxLMe2Vp8nWfisDRWuH8S7PobN0+4QIP26NqcIdQnOBeGHYVJZkEUjEFoLnpTqjlqQRr+iBtK2NKaWa5RCDiQ==","shasum":"dfcfe0bf00b807c37897d60e9305dd258690499b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598960325.0.tgz","fileCount":31,"unpackedSize":42473,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTjLRCRA9TVsSAnZWagAA1lUP/j9G6wi05ViRsDXYojZG\nu8KkPzSDSV1tRDMP4cnpi9xmgKfX3dnCb4b2YiX/Kdj0lTQIVCtnmjmsJUPd\nrri/SiOTZP3jL+uCLK1uYqfj9zZwHe8yUbAc1wCV79PZqxBmezIoxe+smJR1\nRIRZ7yl0RYzj1wa/iWs8MOMoXeyXvFxao6fo9K7t5kleSV3RjQYvyj0yheUD\neUyRDnzH2TWFxo1BDKcul8EX6Du213CX74BZ7dFjG+qCeBU57lrPOhS1TUdb\nc8Ai2Dj+5sc4iu1KzYZ/IUU6QqdOJ28C+Tb9Efc3flCwROl60r3h+T65rYwa\nNoLPPNOTRCUxCFSBH75vVkHEoqb/NwGQ87TZTQYAlluDuROfCfU3OgyWYoq8\nADIfLkuHydc0q4fys0x9OEzamlW1hNYL/tkLynqWbWvWPbHuybSzGRBXCTDt\nzt2UuEFXKbZg6/snTzIp9fFjsBEoAYVpYYhxipyx0Z9SQ3xyVT5kEUAuvLd6\nbciShQeMndldIVpjXvfQTxTnd1G/L/XeeuuBdwx4TWXSFffLIRzfDvtGGW2F\n8+lROnZNV4wED8Br7zwJ4PPkADNiw25e4EbyogrHcCXJilHoFlh9wZmJ8rZp\nzVUwIrKrPjqniu5j/iHc2bXobOGZ95EGju8B8TbCEM3E0RgLRp/I5jOMZ2Ed\nnKYj\r\n=tm+H\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDEzP84setRy65VeLL7FKx9oSvEC+NG6d9l+5W3filnMgIhAMm7D4miACq412NZsnkc4qa7bnirGN58c+BjmZeXQKZ0"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598960325.0_1598960336531_0.9111874438242675"},"_hasShrinkwrap":false},"1.6.1-canary.1598971652.0":{"name":"@joist/component","version":"1.6.1-canary.1598971652.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598971652.0+f6c4011"},"gitHead":"f6c4011b953f89b4e723ae801b877166f7d66ef7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      ${this.count}\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598971652.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-I1GAF+FGNdgT7kyFdVycrjiv2+Ey1pHcE03nM73EAvCuBdJB5lXEUfD/eUqW8y8MyosuBT/YDcaiIC1mAjg4Pg==","shasum":"cd078b9e9febb6b019276c5b23db38c119a9a25a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598971652.0.tgz","fileCount":31,"unpackedSize":42484,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTl8OCRA9TVsSAnZWagAA0IAP/RdSJJlSJLHMHlr4t8Pg\nCD6NStw9euOyPqOxxv801zRS55u3BS2SKLNSmmbz3ldg5bju+VXguj2UtbWP\nKRTc0C7//y4YcYblMu+ckeN+H7ECR4+9UkkbnGSRJsfa5AmidEpXqB+RLiFi\nC8BzbG5HUAnowEh4KoPG5tw3arf3qxdfeibdp8stdTY7+/VE/JWepNUrERJ8\nRz98GiP8kJETncaVfFE/2qytYP/UiM6tkj4awy/lSgFp1U1wEGY8UqlwfQyB\n+w60jydcSn6p0skDUNa/5ie65aVGn54qaXI3xC2MDqYNrVBxl2UGQuVK3EVH\n8b2DRjZtFaWIp0qI76pR5QkyJUxn7pVaUx0r7blVxWppwKvvty3k7gpmDyNG\nQrxG3N7+EyAe0dwGJkDbE3BJ2S+rHrRDZ/ytcWmo8oh6wdHEfT6X/ZFHcpX0\nMLbHmSXUBBG9Y4mLzgZmlVNcAxRrF6Wj9iO2MvZuyGDzFwZURZlKLLXwE1qp\nyLFmFDFYopYltePeVEj141PJ8Ng0bOtzsL8mchJGQHR5Bp7uDNujUB77Hs/K\nae7cZzZbWULPcIVPXIr+3rrgYhFl7M/iHRzsMvxALu6tTxqdsOhEh/Nss+n1\nSd83TmJNyqHTOOWjuLzWVaU3uYyFXhSsAIF37H+9t8z/x7AXt/4wW781YbKW\nJNYZ\r\n=5UKI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCNuTRwkXRbSIw1KJJiwrnKrUIftgdqlpmTETgK+K9kiwIhAMKFPukdv0EkgRADwX9146jyurJbTeYD4aKP7G+bnJFw"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598971652.0_1598971662166_0.7071865392347745"},"_hasShrinkwrap":false},"1.6.1-canary.1598971688.0":{"name":"@joist/component","version":"1.6.1-canary.1598971688.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598971688.0+dc22bb2"},"gitHead":"dc22bb2ad4e7f36cc77b9005db6a8f868293edc3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598971688.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-lKCdy0otYlZoe7e0KH+jQQfquKDlPvCEGLrhTklSojc5WLGYUd0WV6MnyrTuo8vs96mOhKJaPsiPbrJKfGw+NQ==","shasum":"5253ac67598684b62038b41197aa467cbc81148b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598971688.0.tgz","fileCount":31,"unpackedSize":42497,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTl8yCRA9TVsSAnZWagAA6d8P/in6AfcSHJxwFgabMXSS\nHEr+B2w4LiW0dcRFUYZewOwAijH8Pn7C+9Cy1Jhf5jEMm5ZqqERZw5rx1mRF\nJkVcBksI0AIWoBA+7sl5G1EwcWhWSPoKPmIGOmjslEkfaRuORrzOS6ajmycN\ncJq7q+fgMDYKsJ3YJuzQD/4k2kMiF1qiKnxQ5+PqPSGQ80cvEngyz8cx/0Tw\no8wGTAgNOmc8VUdMqF2spRs1pmH4nRP8oDEhI0DTtrILpDVsDvQ7kWCppwi3\nVwJ2fh6PpdTOThpHMdb5FwInocZUG/bRZlx0rTfJb1WiPU4D/OAyfK2guufC\nyM+OcYCA3m/XZIa+U1VCHsPNyl6R3JY/MyOiqPzVQJ1UVhzmvaHTNAyhKc2T\ntLn+ghonBz9hHc9/iQQNdpAUQSz6q0dMCZP5klGTeH08LNo6GNnF1ktA7Cdr\nkz5hEpjOkf1+3ieH7ZxSjC3uqS1u5x/jqISH69pHNNpLj5L5hB8Bl+tMwZuB\nUn1MRWCDOR79NOya4+Bt+sPGpKKvLko0Vud+opOmPklCT51FxlBgEAyY5GNj\nIkgqL1aHVxaCAvOy/2sQp/zwG+uH1FKd53e3jIV9jMGC2MarJW3njXLz8rIN\nGvOMhONQ8yhli1klP/A3aCli/w0cf1wwePdNdmRSAeEQGH3w+jrtSrORjXe7\nwBNy\r\n=dU9v\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCgAl2uSheG6b8XU5UwIpG9mtJ3WuEGqdzYb/Gi1dpP4QIgMk4mib2KkezdXjw81SwmmFXjUf0NG5CwXRLHNpT1Mnw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598971688.0_1598971697822_0.2284602736464001"},"_hasShrinkwrap":false},"1.6.1-canary.1598977763.0":{"name":"@joist/component","version":"1.6.1-canary.1598977763.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598977763.0+b3504a3"},"gitHead":"b3504a3f2b186aad26902d05f8678fbd83c934d4","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { component, withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\n@component({\n  tagName: 'my-element'\n})\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo: FooService;\n}\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598977763.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-cm0U8iwsC6jxFrWaSZ+htq3JbU6EpFBlBQLwZmmf5fJnx2lsBuAB+Pr0PUIdaynvflrygN8jSwqe+JSby7StoA==","shasum":"08295ff03e52932cf36ec443ad373d44db6aa23d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598977763.0.tgz","fileCount":31,"unpackedSize":42590,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTnbtCRA9TVsSAnZWagAATdEP/jy+f3cO4dcrljeWe9lq\ndXAXJJ8qQHUUa3pI2zsd7O3wFeNCMWx9GjNg0APIJzX6RSNW3L6Yxcyzsa42\na/U2WK797v6vlikrkMuDlASrvEg/Tlemrwrf5b+CP6QbYayFwoXEMiZC6ZZ1\nvvH+7/VyOugrYVg2GKiQKbLCBZggA3TEGCI9pnr6G9DfkhoHLoeedOue9OkJ\nZfjTUIPN6Xsv+o3ZIsrYLz2tQ1UsVjbspaLgQ0f8Q7we0vxotIfcnjmc7ONa\nH/dQgqRFmjSQufKZ9BpJzSiv7059Iyr9B3guT91ldglN2p3uZ/CyGeZONOWx\nW8B7Q4XtYT8ZFEOP42YRsmUxmHjQE/e/mFGW8YfVUO0T2cZjeTxpnGeGCVKs\npWumqz1W6CovC9u204rGreJ1GcULiD1CWV8EhXPRC1p7hTgTLfeC1DH88uFh\nSxWJO3wXxSXMWtLzQI0eT307ofE+mkjCwn5EnA2+nUjdzMJh4g48YtlOUakV\nk1BxsPNIHhP4hscCZxw7XgQ5in/SRDZq5hEpBejfElG5KpM9HYUM/OMJNv0D\n41tfxiVcLyZReGXvnwcBEfVLkD8cjB0EsIzMYjJpy5F9bV/rAgXjEmdgOlea\nbGExq/CzJMXOtEH8WHUJyiy9EJ3kWP5tho1RSYNlseHzV/yveaKVCVX89NBO\n5ZHc\r\n=5hYh\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD1O+PO9rDLv4JPDPZpKT1nyrbaFAa3xjuB5ugbEav/MAIhALQ9FsC5LzQs23hdEdmoX2uD+3xyPFQpSoTMFI2Gl03n"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598977763.0_1598977773376_0.9618379944219766"},"_hasShrinkwrap":false},"1.6.1-canary.1598987107.0":{"name":"@joist/component","version":"1.6.1-canary.1598987107.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598987107.0+72df7b5"},"gitHead":"72df7b57909afa467c66a4b081a4c8794048ec37","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598987107.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-UYQhnrtlPQ0Ghk+LQwrShAMdvxc7NJzxSd+172/P/baAOGdQDWOKJ8gdLfurDIT2zP7nWjE74bi6i/F3jJh/uQ==","shasum":"7c0ccc8485f3f2acb8b3bb9bb6bdc96a7cb43076","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598987107.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTpttCRA9TVsSAnZWagAAWccQAJHjabp++cdY9It2rU5L\nEnqQ8dgNFhee13BuDzpWR4NxI4kirZnj0TcF+vttLC+zBjmttoQPtzUy09Xs\nEHHWQDe76cio4wM/K2F132D1iEHwBCqf27+yhfY9cwPI3cQytrNBxDfw7nrX\nC0SGd879s3zbr1A/HBgpBfAtmyZOOEafc18Fio1OmMNa7behwYT9uRtphs9z\n+dmNvNQTtpMJwm+i0aBXcglLJJaq0nLF6FP5g6LSqXnDfE2BAadPc80BgURJ\nowckhqhnV6WRNplRM+ERIa65qguAOFfIrctPldp+CZR6qKZouysW/107PNOm\nqwJw/+apmFFHTDPAZI7/TuSo0m8UL6PzpLVDQM1AbwDDg394f482XwpAtYzZ\n42kYRFyD/ZjP6+qhFWerjQPMeB7lArcGCBWmL8v3fckK+v1lFBRAzFnNn2JK\nkKPUSlEv2ZaRAdV/FfXPSVqRnzqOLO98bVgR8QhCxI3RP9D/IkahYDCLwTuX\nd+3zsuIirdl4t89Nk2lbH7R4S6FYYmrass8nZ3Ke9y637vqKwOMP+gK0jd3b\nJrDq8gxwWf4IhqbFSMWZit2InSA4Rj09J45shYVV1gH2cFe26KLA0/4hzrMn\nz4EUpYZJ5oVW3chBkxaUsfWkYJjpzXML9REgUc9GsgwEA/Eo7PsARHNQmZCZ\ngMNe\r\n=g2Zs\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDOFuz4BLAcMGs2yVl9uL0gzrod7MHiJGm/2MacFjoHZAiA5Alsz2nT2gGnBg/wr4/kryZ/5hd+AB1OVNexHprKxnQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598987107.0_1598987117408_0.2592505585591909"},"_hasShrinkwrap":false},"1.6.1-canary.1598998346.0":{"name":"@joist/component","version":"1.6.1-canary.1598998346.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598998346.0+779f98e"},"gitHead":"779f98e1afd2996caca3ad6f1357c52814e9a824","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598998346.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-iitSIKwHZUlHrI56TR4Ytv4eZpOPCdRtEE8+C3gvmkt/l1+D4ogvbTat27I9b2zmU1erRqO73hCx/JTXsUVVyg==","shasum":"b50ee4464e063cd7200446573f7576666f288754","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598998346.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTsdTCRA9TVsSAnZWagAAVrcP/3I7NmyhfXR+xze6i1SX\n5kjhsUjzQPFZtKCpBpsURerOoW+hoXPdTACLoxp3ClLHD8NRVaJfaJUXNDg2\n+LPIMYucfhJsAaOmjBT4fzSyoFOClfSPZqjGeBALl3fr8lEWLBOLCbAE1J11\n7gqq3M4BGmu1070N00zrK0x1i0oct+9GS+pDnLLaVmJfUVuAbQgq+YIlv2Vq\nIQWth5tL8+AWsPEWJT0OcIp17QXqZDYzA6bmIER4DTJi6pHPlv9IF1erT62R\nX05FgUpxkjc96iTQEDEwrLWF8JohulTkcCJnSTG76HC83RRD/g+HhZDr8miU\n5aUZLx19X0fw888e/sGEgl1Y7446EdVo9Lgzc+5wRwE+mnF9Ro7S5NSGF8OE\no7UYVfSR2NLY3m5iNye97iHSwJClRZTGhMH7YhCUQa+GgxL6J2kJ3hv7U46q\n+TDgdcYq34qDn3sUT2sPAvzsZFyuJbfouZ//QlQHU6NNglQtGTQhvaIvLKLR\n8wNf1boFAg2Eftaf7H9LCuOYlhvqF7JwbAaPAH8PjcIv+HJ5XVcy5MSrtOct\nZbGlNkFcojXZkrntVUTtL1ZWgu2GN+1W1c239QVTMunmJBlTjJcNiwst+dOz\n3uGfuujDMrcX5and6Kh0SonFAAyyNS3kGY5J3ZV54qdi0EJC4h9/zJpDt1ID\n7nJf\r\n=Rg87\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDqmtKtbwIrTMKKz3PzJz6mCERZHpZ+YB2DNCgBRvdfzQIgC/067SjjYWNx+uVDMfbHbFIXh8THSt9NGaxdhHiYSLw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598998346.0_1598998355245_0.21743489962227058"},"_hasShrinkwrap":false},"1.6.1-canary.1598998587.0":{"name":"@joist/component","version":"1.6.1-canary.1598998587.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1598998587.0+e6bc0b7"},"gitHead":"e6bc0b7a2744604aff4f8bfff110d15fd1c6eb51","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1598998587.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-bjOSkpTf8LEqOXnot/GSOU6x4gb8O+WaVSGPomyU5h8xMUIxJB+r+i/UWoi98v7dBSNuwyeDX7YgNnvoUqIZkA==","shasum":"d556b659ba0a9af2862b189de409f85e7c3ef932","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1598998587.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfTshECRA9TVsSAnZWagAAaTEP/j9KKpP7e3PdYA6DqC+y\nxdVWv5qACcLGp4D9fDbkciBbsAu/SUVxH9X+KHJ7Mi7f2rBo2oFdl95/Vywe\nohTnI0PmrVsi9gHyN9AdLQPbVhnCcjyxTQMC7bKvv1EsbY9lNXcQgWJbV1nZ\naQ8M6nfilH02MqcTNRG4rky3dj9mGMS0zrD/qRj+o+FHC1lkDF6254xiowSO\nMtZ+ap0X5GBSpNz6cyyXro2VQ4JAglhZTfFZ7e5/5GC0evKMFKRRJBmGxZ8s\n278Eeq+rkl7s66n57LCo5ixNiHfnTcE87msesi68g2Tq545r5BUCSEaI3pKS\nOlBuruGVLqDlLgrduWbquwgYbBoLT8bfX40F5UJySCKI4sUG24XuakVXhKBG\nk5UK7FrxKCNpl+7F92z6QUMzin32WwaJcQBH+pvXBpMQEf5k76tiyIKOE85p\nSwviVw9UIC2GemdZurrULYH/vpoGgi5MoIEJTWfcYBPd/GSR2xEQ3cFa0w7v\nWYn10t3P0hg7h2tRPHbtKUvsu83IZ+3IcEUrkm/CJhwQwzSWakTrjrFdZQEy\nQnhNKSkX6Lt2WrFNR0hLTOqOrtVrS/bSxh+exf2Z1BdkfIRiQNJmvmhXW0Ly\n1CGhxCNqMsiT7cZFRPu6Dhls/MjS4hedt3H4Luj/6IrQnn9qFuxokdjdKeFK\n7FGK\r\n=vYzJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDkwZKaLgfD0fTerq6AhV9WfRiZM2XPv0n7jj7m4RWd/gIgKaiGP8UTpJLkAXsLLSh6IJim93sR9U0aqTJ7JSd0jDM="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1598998587.0_1598998596537_0.9049082969345268"},"_hasShrinkwrap":false},"1.6.1-canary.1599063095.0":{"name":"@joist/component","version":"1.6.1-canary.1599063095.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599063095.0+81ca66f"},"gitHead":"81ca66fb054afaabfdf1e8969b8638a18c163bdc","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599063095.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-NkX7Ktrxvx71qieFNDDAEb6t0J+fMXq8/c04nqnjciXtz6V4PbS8FtGx4je1T07BRMK2cmistC9Y0OEV+EsSog==","shasum":"5cb4454f453fda1ce2386035209e1e662b4f69ff","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599063095.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfT8RCCRA9TVsSAnZWagAA6FQQAI3xW2m4hYE/F9efMQRX\ns0FZg3Ch/bPDMKoK/TOM6oZjj5L1YgkKkNUicYc269WS2dkItnzvR7N6st49\niGtqT17FAckyNbtPUBzVHFO9tNLtiDymwaAuKyNFKePM0sUJjyD+HKaBlGj1\npcInodpREGOl/VXJ7DVP+0qyp1Ba3ONdFk7tjvTi3Y2ZltgnNwefzkZQTfwW\ncNuXkQc2Vaf5ip/dYehNdogiLiMt5n9Z7vUpX6YvNmvN/ZVLm+qlTgFBS6HY\nyGPgTYr4eWImjXVHc8h9JkAuvSeTXADuuOUECpv98rwhgT2+08EPJumoThnb\nbc3dNeNywikqMw7N9/ei+v/2lQeCJCPpbYYN+yrfRBLYiEmcC2K+X2KVv2Z6\nlShjtAi2lCYcEfJuerZXmuYzMtRDadN0pLWUWgDUZrZrxtlowiBN4jw5/JAd\ncnNx397akn8+4g3C8Lq5YAtb0mKKKId0IVNV+lpwMTvzforHRWXvUUHmRRjz\nrcyhcN0dxJQ2gQv4xH4vUOHFlKO6iZumaqHkXK/m54mnfpYPWPRcKE2Q0AyW\nuW5YcyFgx6+X/omxjIQ8AuUy82Td3PKxe+lSBUmEb7cF5ie4zaCRHyrq63Dh\nZtYbU9i4pGayt5KXLvZDup4a52myyES+5Gk1ce8/s9GguKMjvNRW9api/8po\nmdH+\r\n=2bTC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCJrB4WmyyIjMU2LQugw3ba7fegRn3MCI027a3ZY7ASJAIhAKOIwXKTC3r06F+IlwuBCHDWkcPbStXRkDo9fgiW08cG"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599063095.0_1599063105515_0.11702172727932769"},"_hasShrinkwrap":false},"1.6.1-canary.1599063965.0":{"name":"@joist/component","version":"1.6.1-canary.1599063965.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599063965.0+1ea187d"},"gitHead":"1ea187d8acf46e6669885c546a922216db4b8c3e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599063965.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-uz76XdhCQlHYVfu0GKEwoYmUOkpjNVj2NKeWmsYh7uvu9YDOBLyC/mk1eJa6Sh6jwOnkQDK+HOgLTQyXUm+bhw==","shasum":"70ad23e18aa447e4882caeb3536d9237b12a1b8b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599063965.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfT8enCRA9TVsSAnZWagAAjXUQAJL1w+ZJa6c4pechT4Ha\n4RYkq8N5gu4ikZfB6WRZy0UrGX7kuiW6bRrkLGSN9Kk0/EN7B7mPjF2urO0Q\nKTdKoaP/9e2f6ymBLyB57fiUOVLSddP59akX2zizmtHyuIJlN2jb9pDQ+02m\n5/iB9q9Qyw0tWhaRmi7B5yCGpJWHs1sxn+RmM6vdcJX22NVhi78QLR9OIV9+\nprxLg0GzOUpX+Jfo01C8XPZDfu9oKRJOxk6ar2SHO/DDlGd2FeNabY5YOXad\nJDgOsG+ix9NRsi3W2JRzp6I8EfwSks5/BSLbfPNLZkJ8LbhyFq2rGhfjLqMa\n5xysGQh72LDS/O4yHKV+kGlTCTEBjkOJA4iCM9iAEnNiOX9AmWw/DBBu0IFx\n2v6kPEuXxhjvPd1RkKZpesE8Y1biT69eb8GOHReYZ9Lmm7igsuuAdIeAp3Ko\n2e+ISVyAwOcGoODAIhD9bYrtYRDLbozO70qV+ooSWfvG4FeVUpM04OkMc5vw\nmmF0XHpt/MW6LFXbNAsgTemvGnfCmwKg5Ax2GsIrpzUtH2VjWal9shEGnttv\n7SmR4as0TLG+VkSYO5vZG5EIl/j3yGqrRkKbCzK+6QbFmuoILarDk8/84p6m\nAEAQGeVf09ZZuaWSnuZW7UE9F3cRLouS6eEJDBJdf+F5M0RLbbTRjCdvdf8m\nYrFr\r\n=SEIX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBBwpFRAyRQV0VIiZs3fj5gKutAkkwXRMnDacF1y+YUmAiA9o1UjNnV9S8OAh2aN4vLQJxvmV0aXXZ/A8KNxu2PxgA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599063965.0_1599063974941_0.8641952663229826"},"_hasShrinkwrap":false},"1.6.1-canary.1599076498.0":{"name":"@joist/component","version":"1.6.1-canary.1599076498.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599076498.0+8bda6e5"},"gitHead":"8bda6e53fc5dbee379be6c202e4de30819df0c83","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599076498.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-YELJJlYXh7NMsaM/7qrKmusQGeKEgJWuz6WLdvOfd5ZgLd6DgdRQ3CgRtDsl148YHngWofwjVrZ6frlBCHGbfg==","shasum":"86ae7fba7ca183dc3c71f463e92f565d35bb8ed5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599076498.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfT/icCRA9TVsSAnZWagAA7eYQAIVELNLeZGwF/tRlHUIb\nmR2w7HFnThy2/6Xo7tRaUUNLXdxRBhaxLAELFsV1ZqKVft6eDFQ7pi3LOgLp\noOjt0//6aY6RId3d21FqCvTGxtIvndzvlRS93NHmpWAjNsuE5wiQu15r45iM\nWr0hKUQ/aPiJBD7WJ0lyhq4bYPAojlCMDYjEOGvfP0j6e35fkawUoF1vJjH4\ni2rVW77XDfE+E2mdIve3z8S83hnFP5re1XrkN2J9SVp0QDxtK6x2hQhSCdaJ\nJjT5edih5AAIyetd61KJ6A0r0Ufh8hs75WEwDtsoKn5/CENMasHMMNU0gWA+\nwryM9JpAzV/dX52QL9GfYxUWOMDR8fe2CgIQVuDUugeRim4NUVDnEMg+D03N\n3SV//muJAo3d4MqcM/uqmpal0oPHHieHQrv4x8e8v4yZ6V986KIm2jenXJrx\nysqjGQrQYcb9kyjOE8/6ryAsZdGTHeoXdlA2qz7P+Zw0M8sVIBDvfHW/4eM3\nn52/nTzbc2wi3hJgfVanT/ibEtyj7QO9E5S3NFc/pZyO9oe5UGdbe14Pc0Fp\nZF9V7v2uw5D0/jA5MeXjuWLkXEDzTfGFf5dA4gu4HVkEbm+jIzhb/zHeJE97\n7Xxabu4L5fiWyP9g9Myvwyz2vjfKrUuteR/Zmbtnb9f/euothtvYzqAh0gTe\nHomn\r\n=41HN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD7ZQdIc7tR2z/VwQRCTMbycIDBjcwSiHYa4Xi0dxXaCAIgQe7CBcrPKzm4/PFFAxSLD/mq5C9Qob/aU98weV0nBUs="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599076498.0_1599076508216_0.80938576378264"},"_hasShrinkwrap":false},"1.6.1-canary.1599129722.0":{"name":"@joist/component","version":"1.6.1-canary.1599129722.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599129722.0+a0767c0"},"gitHead":"a0767c00f53a30777e827d55e831c60924fbf846","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599129722.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-+F8CveS57a+fbcXrK139UHbnaV9ObztY5+L0xrXutgBhYL50StK3r/IVX9sLrql6ahTupAvRAhtwV0ye6s4NMA==","shasum":"469188350f1e2b2a055e4eb361c7ed286de1fb0c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599129722.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUMiCCRA9TVsSAnZWagAAetcP/1MBbdFYOogdInNN21C2\nmmtlWUvFkX/HmM117zkCH0GaO+DKO2mdbsSYT0rEGE1j+LP9iMtm8oaLUuLJ\n0F/QdJKf99K6NweHqBnFcE4v/0qFL5MNPwsyLjdJhK/NYoEdC4TBGQdZw3A+\n1B2Y54Yk08g0DAE4r3XRwHG+7pRfI5jL0dkhj+RpK0ry8ftDKk82I2Kx6iwR\n6nOR28f++4mgcoYu6iLJc9DeAsjZrtKCDIQxKF05CEkNwYQ9+dVl4n2/pc/x\nCUQNdrkUOjBxXeS86GaWockBvB6hqTAibFzZx141CLWefDG2RA4uPKDU14bA\ncQPLDLgepNNn3mBaXtIDLT5NHGQ6KgvEo56ovDlXYmlcZpmEMfE8mEzfL5kL\nUlnWZO6K6P2ckznzV2A/pgl9icPyaEzyU2GHDIO4fGTF9Rxp7rroeG11LmMa\nBdWEWhi3Grs1q/rDIe7ooyzf707rwgJkJPTbW5fFAs5IgNye4mIYoHZp0bl0\nUthscYsjUF448sHrfj4qVmeh5VliS5Iacvh/1UoyeMx1zgz+sH5EKfP82t7f\nLlJlem366z9B4jOjtkSX8xGxLw8BqRk8TJlpdGUFDEuGUJnrxTK4gNr3sIw6\nQkXWcJasZjxUfjyLQ/2wzM/s/KTim8ism9rKyBS8B5VDqOBmNpbGKlWgKpqM\nffT0\r\n=mR1M\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCI+rSBZCaz/FWW3lY78NwVybNJv24fvlWy98lg4zO3MQIhAPWixaKgVxExn3EyUskFvLFKgdGLPfNhxqX5YcKQwZIA"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599129722.0_1599129730096_0.22780026655488061"},"_hasShrinkwrap":false},"1.6.1-canary.1599139368.0":{"name":"@joist/component","version":"1.6.1-canary.1599139368.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599139368.0+557bf26"},"gitHead":"557bf26e85bc04135e4126ca83175397c30688ff","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599139368.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-eIzVhssOpFCQM8VA/RC1k+foKk8e3ijzJPRZ+xuU6w2MxRIuZgZU8+5ofO0avbXeFo5QIFMNDaljMfSPU69z+w==","shasum":"e4faefa64699b3d1720878e0e848c67aeb232eae","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599139368.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUO4yCRA9TVsSAnZWagAAkpYQAIJ/i8iChAKiR+hdbBEx\nP7N7QpJsNn9kjUGEQ63Om0jHfxeJGQG7n3L2h+a/wLxM4+NXmtWm/NXFWZU0\n9SNHj4qlQ3Yr9lu7Iqn2+VyYD6umhYouS4kUEXoiz7dXLcKGaojKlwefRoZ8\nWX9g/qg7baxliuUYX2+iNX8vsJYT3BzQ/FedgkkEC097lR/sgux1YbyQhW64\nfhuEMciMzEA33PiU1s9XOm+Jn+MV+2+U3mySZ7OwalKDMF3ceo25LnFn/xWj\nm2y2laAKMxMympVlSZ6K7Rvb4g2kXOH11oLboNDJ+y5i+pfQ0BeZAhtAwhbl\npW02zMtU3q21mTLbhxz11rpm0iuD0enV/q4bURMQzexEnbTtNDsiDp3H1CNx\nmA4z5Tw0UQAgTr9omuIhlujtduPmKUdWYYvpPbunc2rnE90/rgpke9GJeXzj\njtTeHuYBuEyhT0tdPQXpUgaEWIkbOT5OmyhxdiEI0YY2lfj0ujlF/Dao5npX\nLH/K2eXpQv2J+2GpdVXGjdkFTeurYAOSqMrt5YSC5KyECp1TgZsd47xmyCJP\nO9matI182qEJSgUfH1J9PTmIMM+4D0SS03/GF2PcIC14/yLwvrHubuy+Nq1B\n8SJq6t8poC2guCJvC9CSY9eKqESH2UZ9B6TG2n3+lHcn9HIwNCeTnk/a9Ab5\n70tQ\r\n=oeS8\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDPvR3t8EBmK5/6uE+LHnyFw15U3mJP8juD4Moylgfj6wIgH/B5IQq5UtfNjX+LWtVVvxxSUJGak1DWgXykbeHJH2I="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599139368.0_1599139378040_0.3686893049673652"},"_hasShrinkwrap":false},"1.6.1-canary.1599164947.0":{"name":"@joist/component","version":"1.6.1-canary.1599164947.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599164947.0+f89f6f9"},"gitHead":"f89f6f9723420424c38ff28818120820903734b7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599164947.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-SQ5lrv2Zb9BivWhh3daTtGQ2gzC0SzHElsYoBB2COldw0xD1sW0jYMQoh8Uac2r/FMsWkXBS1ZzclhkRnRNZbA==","shasum":"ca0a40dc95eb598f521bdaa0df9d6cda7c2f27c3","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599164947.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUVIdCRA9TVsSAnZWagAABB8QAJ+dIp3Q0SpHkrtN/Dcr\nCbiTZFhVSluS1Uf+pIWlg7MVE+AuVyzQ//gKwtWr0Hn5YilU2eShvz1gAeGR\n60of1+n65GptrmGICJas/uQBmWq55zHJKFnzc4LFnpuW+OFnSxukjb0lm+lI\nkKGMSbPcTeZr2OYwNYCGIB0Mm/BuG3qXkWqxqHaj+wCG9JACNLpWwbMZApeu\nCMCEc81PB06zwHcUsXQGdUArjRo+IbhGxQKEZgx0EZACNz/wXihMvXAD6gTA\nRSF3kELm1p6JVhuM90Nb+JSpWjw067GGbiCJe5KyPBmMhj2uL229Tt1JRCD4\n0gnCveMKRmMj233hc6fBrsVZZxPnEmrH28T63ZxrbwaZYQhnu0r5mu9FbxsU\nY5o9/DAgIV1PyGv6BZAalIHKyPAbTMAOeP2TWo2BHZYvFi+V8XaeRawS76OK\nqF2KjeJ/3z00kE1cp6f7Iodzzp1rEMHJ9frwMWSostxZilWw/qhV4BtjjnIM\n5BqXiZcc8lwLqqrQxzmkCNaUTdjWoHayXyHYrTpbICW6Ibs8bfMzDn2bfkRf\nb8dzhnGsnWqXbLxmHsWXf48G35CQZBXslnhka73AwAUJQJrPdyPRY1Mx+jug\nXgHDj03BRL2yLLvs4VFg/dE5xRNx7oKC6UZbb/7KcxChCRvXBTKhYg4QXan7\njJbD\r\n=MxCH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDzaQhwPh48HqjHdqj2b4034hqecrFFY+5SWEJ9L8xLaAIhAPZ+svSwNWRJJqB7pRLtoRsFw2w94o7WFxQSlf5bLGNf"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599164947.0_1599164956581_0.3378760534460554"},"_hasShrinkwrap":false},"1.6.1-canary.1599224463.0":{"name":"@joist/component","version":"1.6.1-canary.1599224463.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599224463.0+dd9def2"},"gitHead":"dd9def25c41350ac8f2b84971cb95a7bec1bda42","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599224463.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Q9C5SXG+UOg1gz04XWZI+L5sV2LNa1VL+KqLbXvTUU/Xf1XBlLH/no3Mk3tZe9kgZhLLJiKLM3WOTrT1qb6H4Q==","shasum":"7cb5632451a22e45d944ae32c9a9257350b14ce6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599224463.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUjqZCRA9TVsSAnZWagAAAAkQAJuZM9+ZXBEhoWtPEHxU\nvJr4zeSpmTZ3+aYJ15YtQwrrzEALEBC6lanzs6vWdN52/yW1Gz6RBf/j8BsN\nIwTCrlcWoFFbN/jILO36fFL1yeBB0roeTRBxS3fuWj9kZKwswVuzAGdW/yE1\nds6UbQE34lHp83nYIRrTEMRLa8YdKUWhpmEh4kaEs9RQGM9IprDeqN8oBgjB\nkL9MmseIyqvaDb2JVEBQpm2JgBJMeQLceRp9YmoVtMKf7v5tr7M2smHrgnix\nd1AWA7MAUKms7A2MFzkh+X2G+mVW+8HpVPeutIVqIGlQ0aTuLaXgzXUDsWVe\nIRNRjyZdLSRQqqwnBVRaoYVGr9w3CgF3DPYmsYLoc971r7foLRHv11Rtt8z4\nAbPZBVCg9xMZnqYjunHE6RksxXk13snmwHDdbrNxiYmjPU3+DfRpKEqCUpH+\nRRf7FMMUtZM4CsxFeaTs0grBzQrETpU9oo7gXwG1J2y+7JIxI4ztjsWbjMaW\nJenf69q3Q/LtqOE0VuapTiDK/30Hvvkl7JV9rM84bIBNQUIOnWoviBCB5kD5\nfT/H57zsgKdH2phtgPRnxCLllX9dv01u3LSoOHSytmVi2kcyf1wakqo8eOeW\np8k06FfZ8+Cn0b5A/QTI63gh/6csfXXcEmInUxELMj6lGZk/SsDY3JEi9PZn\nzqM/\r\n=9YmV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGmg4JSy/wfPCxAg98YnEf73TQWRknceY+PLwGQOhWpjAiAnACz2Eoqh0pfR2jJaBhnntx/0DXkXKEjoEUZGv9aTWA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599224463.0_1599224473346_0.8375971147799186"},"_hasShrinkwrap":false},"1.6.1-canary.1599257919.0":{"name":"@joist/component","version":"1.6.1-canary.1599257919.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599257919.0+f590682"},"gitHead":"f5906829e357cf28475e8ab880a042de2a52706f","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599257919.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-JAjYj91vzrF8nGhQJjo4gtLJZtgOiUq41rJqi18GvbumG5rTL1oic06GVykT6KyNhQrMtNWHK0FPgm1VWG0DwQ==","shasum":"74725d6dde00c3bf88c410df81a74b52ff96e552","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599257919.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfUr1ICRA9TVsSAnZWagAAJW0P/A0z9yGfW2nbxMKHCUoT\nCxC6K/Xp/dldJ3MHNNaszgPVWhe9WHRpTWvilctzmLOA2KG+p+2r6F92hRul\nhFF6ttTJsA0vfDy/UzjxoI3W+d/BEyBK1XsNaQgyHLvqh+rtk5cJrXdDiauD\ncJae9p/ZaflYPm/2c95E327IZBjXD6z6Gwoh6MeVjg3HB1uOiIWpV0NpLXkU\nYD4MMaYMa5OMOuoB1EF2FA8rax1WkzkKKNVd6M41+5eUP4BelIDcGMd34rhH\nOvsrzh7xLka+KqaLAW3r19zVh+0zUsdtiatxKJb40GbfW+1E7lEJRZvH7J0/\n7jSZGAVUiX8olT8/CU2JJm2pbj6D70y++yC9NA47tRVvABV7tZ1qmnG9RoJs\n9UjuBV8UMjLyUZz77p+/6nSUgfEzxa03pDg+yMj5nEZFMllbc+hcp7KVdfYz\neK3fPpynLLPMU24n8mqU9XJlNlc54N3+YB1E5mo3Njui2JIuS12m4xscC2u3\n0zy5oAf5AJ7/oS5QC4x0+RYbEA5UcCz4Tx0OSDz1lgodRjNRRBYT8ehVlnjK\nYWqanT5hKYFAcPKfTwD6DjQTow2CGu8vextvJDz2XrmTQmIR5Jy2fDTpR/Bw\n6erz5Y3QyUNonOMaW45/xLq+hwBz4WT1rDjlCCdiXnilUN7Cpw9ep+WtvFoO\ndlQ3\r\n=djHB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE0KcWuKx7me7cK+ZQwcR/uA+lYQ1lXjtTwiR3vi3YpxAiEAj5FT+3GffkTsgyJvbeOo01EYuFNtKFVuyDMfQEqZ2fc="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599257919.0_1599257928402_0.7316368177147985"},"_hasShrinkwrap":false},"1.6.1-canary.1599418898.0":{"name":"@joist/component","version":"1.6.1-canary.1599418898.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599418898.0+1e4b5c6"},"gitHead":"1e4b5c63379db13855c03b5fb9e60ff02c8354a4","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599418898.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-nKQrkfCZgWzXKr4FvZYr70S8OcWWdGlKHWK2OxL8paFYhZ4gjnhqjFg63GvEALyV2Sdeaw06ZhvCa5P/OjOtZg==","shasum":"8abab740485c1b40f197fda25316a8f30caefecf","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599418898.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfVTIcCRA9TVsSAnZWagAAKQQQAJCXXcTYfcLDc1r2YFmq\nqzGTk671HxkHPYJt7S44N3KJY2O9WSpwBhzxe2nlVF67NKATaXckiwEngb0g\ni2yAkNydDlfY7QUE/VG3/1C11Z95a7FR8uxEXZqSa6maVwSb7qdjZJrSEwmm\nzvuRE3B0wtCyN68p5gEtMjF1BYR6qV+tKEwq3ZkZg/U74HwH4LEaGTytqHoT\naiYO67ToUlTB8mAMMkRUv3IRs++LkSZAek5ek4Gp+9IWPQD5r55uegowZXHz\ngaDfsYNh3oStlPafKheylnqxj5sqK/PC+UKJDzopkk5nBH3BbWwjyYX7eXWy\n6HfNgru03RhFRgdsx5nFIyQATqncnePOqYPWPH2A4snfsMA2lrvuIF29EDin\ngpWkNTJ0XO98TFFSnnXJ6DiOCg4Kjy/nn1V2QbFzPWnfY2AF/SRIHEfDVFnV\nAvyJCdbcCFM3wZ9uQo9WOmTEHUq99VxK362UhRsUqjDBo4MlyTj2VeoCzYQ9\nGbp7olydsTYE+01bA7qrAEBUHDr3JI/xnxiWYXv9gDYEyCZT9NgS1P1ZWpd2\niquhPjplBc6zKT1puUbT0YLqklSCV2/qBJen23Rlr69MIMwca6WZnGJPkaxl\ndAJu3oLD5n8RS6EAG48ZswVh8Q6vxhSSaJc1aZiCzdx5HML32mKlJJFXVEYT\nXLS/\r\n=DCOQ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIERus202LPFcjMgwmk4HbhekWl07W6QYJTZA+5CrIUmMAiEA7HpnFnOf9zcKJ1FJ4SNHdKNx1DALx1c/mjY+qLGRReo="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599418898.0_1599418908080_0.6160952236383375"},"_hasShrinkwrap":false},"1.6.1-canary.1599477682.0":{"name":"@joist/component","version":"1.6.1-canary.1599477682.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599477682.0+b67e7ba"},"gitHead":"b67e7ba442c015d68abf99066f41ef7f4b7af6ae","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599477682.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Av+qcEIYVFc/IDvfh6JW0mTy2QWBjZ29OqhE/DU5xfvuNbidKyAdIub08K79Nz55SjlD+c+PTsuRb4HZE6ksPg==","shasum":"79ae72d7bc91eb8d463b11a145f119bebca0f890","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599477682.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfVhe8CRA9TVsSAnZWagAAKjwP/2StKHLbyL/JkNxkEmQY\nBGLiLiHk6jjhRbKCgycodvj4OCbZFWBxMX3H0LFrU4uLiwUuyVCLcQrFes0l\n3ePBX9lkWFB4XY56sQHMctKsSLE3YMENuQ6s3sI/W05WcJGtwxWrJZON+muK\nYe0+8a4CvAwPeVj33P+MHSdaDY9ruk9SOA0JYNi7YG51jFssWHvz2wIORWMS\nZQ0D+XqiDg0XWQnURihbw2kh6v0U4fVpwGebhfRqTkBoZ8LsYIOUAKBWiNHB\nIUx5+C/JgpnP1uIcBcgw15f6dTXoIgC9IsUDYxoFEQ83DQBsEtn787vynnsi\n373aVuhV37TnUFajQSaO7KeIhhl6Vhm9G0BfqbWHSt3xMJsHIENjeqWpV7nJ\n9qoS83zE9OVu+a9TAUrCktpF/E2YK09aVuBKMjbRZknmutHTX3qWmEX7hjya\nyFdJ70H5Lq19pT69WVFto6HuXpvBLPCA2+O2G4K4n9Oz4ndWO8UsA/OdsRhg\nANLIo8Iok88ZBiUoIZZi91U2Pt7ICFDvh7lSKOq6Lsg21a2lGQMEzu6CfpTr\nDmbIXZNlCcoU+yLugnhXajgxAjXJ1TRBmwT1PDAKtc29kXoeiOmyPbCsyH46\nFYhVXsTF8OnKbZuczE2ee8EcNqVjB3vMWcvE2gSwUaqkDpH5ZnmMC6WaY0fF\nn/A8\r\n=MRBI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGqKB+MUU/kpA7kJc/tHJ3VS88n3+NlToXN2oKwD7j6EAiAdRiH/BguWeuxZIk/cFev6wscfaD+JUQfWWWZFtBpfpQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599477682.0_1599477691512_0.33554552348552336"},"_hasShrinkwrap":false},"1.6.1-canary.1599569957.0":{"name":"@joist/component","version":"1.6.1-canary.1599569957.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599569957.0+7e3749f"},"gitHead":"7e3749f6b5322761babb3226aaddb1c1c9d7af7a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599569957.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Xs22yywT7/zAD3xeaeM9H6TWGB7zu+VUa9dxlHttYo0+AEIbXp2Unmvpgchf6hMg57ExPM/jVvSy0i3+DgwVLg==","shasum":"14df47b540211668683bfa6fbf28f96f0c32e309","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599569957.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfV4AuCRA9TVsSAnZWagAAUlkQAKJ52lknwsb3kmhXdPXi\nAprZhHYs6R7fv5nnDRp7wVVfASeHfsy5D3l1LSliKZPwn/xd3LLF50nz9TfP\no3whDdjWam18RdEq/2vl16nvwvTXqP+J8M+B8pBHrsKs6Dd1yTl/3P3n2EIP\nZd4NAV5HGHRMxP0k9ZOFERd85n9RJHwiNQb63BvzEmzgy/4w689+PcneSVS7\nWVvxzyy5bkjI7t3fDalmIJIURZnlcntZMmOgSNe/h/UgHtv0/+EnuQDh4eGR\nwkDU7BdTpEkwIwuqqR+KovDZBDagZYe7QH4vP0Y9rbvPR4n1evshloN+iUKc\nDUx6JXZEt32yJRU6Mnejt1GWldk8t1ororNCilCjYGnCOQdcA41z7no8q+WF\nd7RNGF3t14eg0E41QjMBY2jT1T+cDuHneTt+OX/jA8+iz4IlkckkWVapateE\n/ngm+zPhzQhVfc2ZVwg2aLE42KpHylHOYeaaUA+ZnZERQgPazL03IdZoFPHs\nrs9tax4+iGLLyIMLFz+Vcd5/Krs5EsLtKfSpnp2fXWOyya4Z4JlA9zszUjnW\nlE4IA0fWUqvKKEoJwRuWjsRzUhEoWZyk59rGNbk4UMzuOKEKVHAsaGer1U4h\nE2vth6SLCQFHebYFfGa7LVg1XerKSMLfHJbVJvCzaN1Iqe3kynv9m1NkND9x\n2qqg\r\n=r0+j\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFDPm168XgfEuRu2ZPYf07smgEXnY+sK2sVCalL6VV7FAiBC4JAtiQnYI1ocD2VbwyosjqjoGgZvDACvhA7U5rqZhg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599569957.0_1599569965878_0.947713547971782"},"_hasShrinkwrap":false},"1.6.1-canary.1599569997.0":{"name":"@joist/component","version":"1.6.1-canary.1599569997.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599569997.0+aba1683"},"gitHead":"aba168376f056d350e6294c9f17526963c51aa9a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599569997.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-QJFrTMrhIepYCj+oK9bEy41dXOXUxrwuoyfybq14vsrGrPk7HK6Dwur0NhbrQPmpl3EphMM57TfOZ90awJayBQ==","shasum":"77fe9772ae09d8ba68928b9c322d965dc1c46155","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599569997.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfV4BXCRA9TVsSAnZWagAA17EQAIRaMWVu5rxdHrAptIkw\nRuuo0AK+SpFFWkzihK6XEUhVyIA36Dc4Tk5vVLzQBEM6hya7f4UYtPhIkZk+\nGySpU7lmHMeTnBonB6gcbtJpAhcNzlqm21CWNWu+jckzivrLjBBVRlL/N/N5\nGZI+zbu3YzBag4kdlqRSxs8LdiO9Fg48LxTGhI/TUf6vYSJpfOSUqNNTS4WM\n1kIdWXo3252AsjeDwB2RSQ7tivn2jt8OaRU2N+5g31fYa+xEEItet6NlvjwG\ngpCPz+eimHa2LXKQTLF9rwra0V9YPgJPhhAjSaUKJ4bj3FoXrbqd1NtDrpkv\nfaATIQLbHzqfTh02cE/cLJNCOoRK3P98zwFfwo01reeLf4k8X0WHbnOE/lTl\nOciMqxqhl2q104tYE6N/K6V7qpYsLfd6rUFR80nSaJrRaD1CLHc52Z0f34T6\njYrJAK+15QURr6Heu1jVRQ03N/pCm24PFwz52xhDfmxvhLf55WFwsq/4gdch\n+Lj+VFxaqALptzc9Hj2Ni1qFuDdFOBpR3PIati5E+2O46RapCLFkuq0mc57L\nrY51eQlfeKa9It6VRAp3+iFYyt0OlZWpLmVrpyMimW+sh5/KYMm2TnTQ9chY\nHyenrKMKvsdfLiwiTItPAiBYj0z62wpKZsZWDGu9BU3fr9+m7QVNzL0mWpfN\nTDE8\r\n=4va7\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICJgFuxj2uyY37wC+pMwUXIADmbfo0sp5pCmQ6+zKzwoAiEA8DfDrMyU+dFFlFA+PmPIwZleUQz/Ycbk4Xt843CeeiU="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599569997.0_1599570007071_0.60112270978944"},"_hasShrinkwrap":false},"1.6.1-canary.1599570015.0":{"name":"@joist/component","version":"1.6.1-canary.1599570015.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599570015.0+65f76ad"},"gitHead":"65f76adea39939e4155e63255ad3950a3dfe1e9d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599570015.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-fERk9iZS0oqyHuKOnVa5P5XvjOwAPxwOWfhrD5wvmYLCPKttrNafxPhNhuzGg2+5m7KXSXzGI2DHM0EpCi5X5g==","shasum":"5dd5db96a7ff486d011a7ca316fa36b7d0c24a8f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599570015.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfV4BpCRA9TVsSAnZWagAAkHwP/jb72Mjj8zenEfXtTvBH\nusQBHdft4jyB+IswcMXtscQSykIQxXxeWzS+MH4aXSsZ8yZm4YabrXe4HCz9\ndiB72YwBaiCs1bqHKb+Av0F8s3GNnRC7r4LCc/XIk/K7+RuoJI7UjeWzpqAG\nQKZEovCzx0Z/6qT+AuLucsrXhvBpFobUEm+zLAAhOj97tqjK0l60MUZI9IHM\nQZ8b0rHc9NaAVWblZcMzBegL6dKybSRE0bV93ihNQ3UGR+xyGsDcAPMHN91D\nHZFwJ3psWUua4FiybreSvbXqqd7njy9gR7ODIn8qMPzRGINbo9387uFRCEkC\nNsxJ1ekwBrKReclhfvLQo51sZwopNbrYadpn+40daKJYhVQIdxo2e4iTS4xu\n8hWONrE8Qytsij0gHn5t6eUfgkGexlbqjbWfwds0NTCT/OB4c/iCkbIM4XIN\nehX+edp0zT40Aps8R4Y/q6igbihIbpCPWklSKthv60rXdLy/Nd/hq7HCBmDI\n3lYo3nx7PoLNhF9hQMGlhYoQIaxfq7/zaWot2GhVqnjBKv7TjN7q7Pcu5O+Y\nqDUA5dwKJbxeKLORiWSmzXzjT4Y8oAdH3QEVN9iyyLponzPoqVNiy05rB9ZH\n9w052jvAOKihY78WRYfQ597oCwFbl6Sf9E4WDdQjDmfrzURRtHN+CQBeMPBD\nG6HZ\r\n=mh/X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAaWocwYWg4o3j2IK56L7uYjMEE9aorw9hv82ZzeCn1xAiAMPWWHtU5LzrsZxVwT3G58zZmnoVw8IfB4XDsRXQIvlg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599570015.0_1599570024939_0.21628047696660824"},"_hasShrinkwrap":false},"1.6.1-canary.1599592429.0":{"name":"@joist/component","version":"1.6.1-canary.1599592429.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599592429.0+816fe12"},"gitHead":"816fe1204a2ff56d6c62eb8eab1e934008adfe63","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599592429.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-AeOP7HyRqmpcp7K7crS50ID00m1BFzZ5qXE0+JTtpTJPvHFEgGkVsGQjYdNMZZMkX5ARH1Jy2RTDCv6QaMJmuA==","shasum":"b82f0edca445af129b55ebaba9f7aeb6fa95745e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599592429.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfV9f3CRA9TVsSAnZWagAAeUcQAJlk/uDX06tKbJj1h08+\nkZFggJre5eNm5u/t5Fj6CUvsJphRhqAv60ffLisXnwkKzyB1WjUBMTJcZsL5\nzr65gqqbfRhKVZrSOFiM2lIdoMotEOYZeAAAS2TDK/zXDuHn3Zr48U+XMdCj\nKWmPYpwesT3QT1IiLhdobMO15wLfDYdZP9cHwfg2W8jeFm1SfjtKZ7zO0fAs\nWqjq9aJrlFlH8loIoaZqyQZUMLU87U9nKUm30xywhyRBcP9m6znDBgaLk4hB\nnvEQNOiBamk+SIxxeo04qbRiFwir/6a/TiLCL92Y09ii+SZLat4kqyXN3JHP\nV0LV5TZCjPJJeDivrEC7jShfccIbo6YbC8hd4OErLnYpAsrdTWm7TrK7Yj2P\nqwYGcWq0JqYRCrdjaxHGExZgLF0E9fW3yNWECvD1yRxuVS7ZIQMQ5ShFqImn\nu43l0hIn225iw9nxgZoUzBwlPdzeZkdazZECvxF1rsCkFdQS2nO2uwtX5Hbm\nKHeoDDn6b37aIKZl3vB9cWb8yVZizKRnBP9cTyqVioztGNz1TWyKNa6IVHni\nnK8ViVSa2oOUILhlCuN6rlp4UFGycTFnN1q6gQuP8TsEswR1DGrqj6af29gC\n9kQ+SPddNE7PdjlYRmKD1hWXrHPioAcwiKSMi7NaI13MyaEWaXH9xKyDpAwH\nIxA8\r\n=tQju\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHyoyVmSVWmxmB6JS8pRk5tW2i3z/pz39C4VzjXSSRYaAiBN36925SPEk4yoSPeRNZlP+Gkl0IkyzBM7sK1UDeTS4A=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599592429.0_1599592438577_0.08109674562070057"},"_hasShrinkwrap":false},"1.6.1-canary.1599592446.0":{"name":"@joist/component","version":"1.6.1-canary.1599592446.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599592446.0+24017d3"},"gitHead":"24017d3c4765eac08668b9f97e33fe64e69aa205","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599592446.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-vzcb2T6vadsT0BU1zbhYDkQMKunUDoxZXR220mf2eagZFHnsD7y/zTMbpX3J8P0H3OTgD68Tbqmojz7Bb/RAcA==","shasum":"7bb799415ad293697f4b8255bcb72cea8d6876f6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599592446.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfV9gICRA9TVsSAnZWagAA/pEP/R7YZLxHr/csMGtLBjf6\n+J8mrBGrd/iXT74Y+Pcrrqtn65M3UxaZCW3AguTlD8xwKNKjlwwrvc9UGB3/\npTcIjPKkIfDjrr+eMSuWd2DSq9vr0KrbA1TO3t0vMGjV8D8kvwckRAJknpOe\nRrUmX7oDOVAxdhTlEktrxvcVQFQgu5GsnhVTkQs1IdWfpwBqFEd2FDzms80i\n/w9jUAktfwBQ+fxUg2KHxUKUTCu+iLIC+V7vZ8JxqY18/TW9bJ1T+gHugIiv\n/KIwvpTt3jgYXFC5vQi+Mks5r8UlBlqWXvrRkQGjSsiBi1ezTitS7PQIIUCd\nxWiYvQwQaUFoQgiqI8wDqjXstURtTHNqFvNjm/F5mFOSXGeOPEt4vspf9hEF\n8v7MWHFIVKJlsQMbz+7KMPlURJd1lqCSxKvFSbeUz/UcXx4sL9i8Ehmv0kLv\nCQhVWIQoRl6RCyZuwX4zpI446uQTGsUaWT3U9gdfBaekEyawOrzscI8CY0aZ\nGiS3wNw5okS1ENU3UVdQ5jRYz0BOOtlC4n97KekKntZAebofqdrJMhzi8+of\npQlB2Yg3TZVxe32B//fKeEWIY3rfAQhoQoSghzccGQfSUOWmoJwliQ6YVS9X\njIDMqV9JmIzUhViyrBkM0E7636RUY76wnZo4VVxfoXXiQITSFUPzEwYxhq4B\nGE2o\r\n=KE2I\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFsBjkHycZfkEfeeG7kDGuy/h/L6H+cGonGwwVjqqgzsAiBRl9hXSLP+73sd37D3HttuUVzK42oAu4E0NkOit4yzlA=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599592446.0_1599592455795_0.4178020428149498"},"_hasShrinkwrap":false},"1.6.1-canary.1599595014.0":{"name":"@joist/component","version":"1.6.1-canary.1599595014.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599595014.0+c87a016"},"gitHead":"c87a016d8ada5f2c091102b17499c806efdcf9a3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599595014.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-Tj/mtokFYG5+yD7mYr0JUFwmzmPQa9SozGYrqqTCRnX+TuzjJBTmUmJOASCsvJ2NXqEdj7YGiVIK4TOX+JfZuQ==","shasum":"b4397eeadbc64c167692424d89f815995378e7f2","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599595014.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfV+IPCRA9TVsSAnZWagAAD1IQAJAbyp11gkh902YqoTrR\nDMAugajbIn4iavVrDaY2+0MDQGoHN1HGbzbB3F2GMrdM0zwPAvKe5blS6ZoD\n3DzTUUpXrzzaoFtOpe1pLNO920g2+tUhR1AujAcZLFQQd6q6hpf9Paiq78vG\nQEnr5gVpa1fq9SktQZ2K2Wz7NqVwWK1fMMjWfP4aZwcu3lTsmInVCLrMFoBv\ncgP7NJSfYF1ZeIe/rNNdK3NGK7gRsXBNEZxxJvPRJBkz+q8Uei2H0QS1oxOi\nFDur3++TdcsYNKRcUxpvLVEaS1wrTC33UOcC0OfgmE7DiOpqPnM20gYQ1+Y8\nZRztRVnnwmFmTty2orHhcJpxlFvSrHur9a94vtdi7mbRzBvNrHH/JP0NgLgU\nn0IGHVKsutF3l6D+nGGAOr7G6CwuDodkNI5oHy3HTPc5+Rz382F4NcC+gv5o\ntOIyzJ/yp5/Vvix9FneI3+GDJreHT/ly8OV6rCuOrbsgBweaAIG4proGzo95\n6B8Ga7EzwFsofdUQ6UXUuYjMVkUOiKW0N/s4G4lmle9wzumZjBQm03D2yxIl\niwGSR/HPTB2My97N0qn6I1cY8osZe9PD0t/TnEaStX/7FQW4HBGphAlEbdSq\nHR5Zsz8pskd7KyVcAm9XYZcWuR0gwho/hkq0U6UBPN9LI7furcYC9rhRYvWj\nsL4C\r\n=0Eth\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHca7W4DUPVFVuodAug2Qo2Bk6/TNapfW7sFo+Wl9bh+AiEA9AvRfQ1adWqWDmAuFJjqss030zpH4/zviSS05Kb8XNg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599595014.0_1599595022704_0.3866724836990818"},"_hasShrinkwrap":false},"1.6.1-canary.1599607914.0":{"name":"@joist/component","version":"1.6.1-canary.1599607914.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599607914.0+28cca5f"},"gitHead":"28cca5fb92758e6b0af45bf8a73d28644304d1ec","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599607914.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-SxsVxe9+rnYMmi9OTks+8TaxFpLua76XwO/VYSbuviJOfZb1a3IwnovQoRAJxALzrZs6Zfjt+yIqkiEFUw5HNw==","shasum":"7f84f2485437e29745a0198afb6b8752ef0b4420","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599607914.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfWBR0CRA9TVsSAnZWagAAZZsP/0F6mbVeii+oATf+6h8g\nlE8vIzeR0eStqGlYuJ3XiV2z9ehETxopwOPvACjoM1hy5hIV6xdihtUDpuEh\nwDuWeOH8pmDKYfpbwkebcdaDwYLdiyFh8w2oP9LsCMxbK7y00rFJKo8gLeGY\nL4XZmODq49rYK3adVANq3Hk6L91Tho2bLZqMnyv3D6UxjtGaAsV5WemgEn55\n6CY/LC6mb7EI5QID8UjmKW/qdV53GdpE7rPZUQHTYhGKQBTAuSF5SJwD9hPX\nMEpHuuE6nTyR9Ob5NEznKv4Qxjc+exOKe10n3nVTHOR13iq1XYkiJFnpCXFq\nC1s9CmGczZnPr4a6CsmC7sI4VkHrkxjGWZ1tyxOXN4j9uhPfJQ5g5fsBxE5s\ninZ5cFSUjvHDMPhMWztvqhRg4u/ABc51Fz0lRxZSEBSyLjtWeXHUm4i0wflp\neog3Zsn2bajoUYK7V2csFWn5kRY/vszj2zIdAZyDK9SSye0krcDYgh2QrRzy\ngQjAsJ4/Xn8ge2rmeDR2u1Lh7Nht45thwUQyOGyJ7i2xzGsBy3qwAYid2RAJ\n0BrfEVqIWC5UJ/ltuhyFVZGfeyeyLTa1CB1vVSrO09NH1Tmk0V0EfF9z7JjG\n9FcyVc88YBKNJ0N07gralg4/TmhU755vqta9SkLbyneqDDQ1poFPAsnm3MDp\n3bQx\r\n=MOPr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIH2zrdHNeika45HXZSmm+8i7nL8qjiDL6LKRePxbGkkZAiEAwWHgy8MOg27yfl7GOTCvGCi9rKkh7h+ZdocSyDAt73o="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599607914.0_1599607923750_0.27599940710642246"},"_hasShrinkwrap":false},"1.6.1-canary.1599670545.0":{"name":"@joist/component","version":"1.6.1-canary.1599670545.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599670545.0+7765c86"},"gitHead":"7765c8613bc944ca003b39fff22f2edcf67b0440","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599670545.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-6eRJLKSZoRKIaGfAzLaufakh9UOx8HDb8enkksuKqZKVJTAMudKbbrxeyllJ4GzzMEtf7SuEezQQ1nQlpjOv6w==","shasum":"89f8cc3bd8a9359497ce99176fb2ce7b142d456e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599670545.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfWQkbCRA9TVsSAnZWagAAyQsP/3cEgF4KFIIJ8k7sMBQO\nGNo06V5/MTfDIZZgCAJX6ya2k0oVi3MkuXIzB0Xkb/PXPstYrn05wEx34LpR\nyW0EbUDxFEIpMFXMkBJup9ol/Dj/jOKPPUvFtwuVILaO1pBYItX7i/TIi55/\nNpvtqFslBWpGpaktlvKb8Npmjkifr6MT2T2jW80XdUVrRnDU8umMVDRgenm3\n9p0s71WOpbGrWv4rLFKQSu9I7y0oEZbh881RInbdd6xJ9aAHuCO9RcUc4Qh4\nLrb+XwE5owva6CXTPsK/t2QtdEVZGjXXz0rOxlRAUNQyYd6qNnczdBP3OJgw\nQPfYEMzmuKaUyxpADHqzpZkq4gaTlhddxSETMivDxxORPsbIkUC/IwQ8WoHU\nBmIVGw7MlRlv4WYUWZCwgd17zeX6fJQS1z5zXt+4pQsA4aGHYZtIfMAVwKDS\n7BdvwYD8JQiLlqUT6M4RDHKLJ8ujdP2gT6WBCCjXqAqxyjHXwMXO6NPiiBo2\nWWop4B+53OYpHsV1fOe4DqzwgMZCJvURHTsEUhfllCimN0QOqcsH5kZ9MY53\ntsTRn8Q1Hhr0ufJ/TsxxRVIOpnnwT18bdMHcmau7jnahWl+iir9i4hWnONx3\nDJGtEU+BNYNOBLDVk/KqzzxhqrpyT7unfcOCEbGOSGOq2F5L/a1V1BOaSZL5\n8agg\r\n=hqJ9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC5hnDmE/t1SaAHuK7kBM6NaIUbvcuV/hT+P/zCegSqnAiEA6EJJmJOoIAps5bLyOQQCECnRlyw3qc4Vwusot9fK0NE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599670545.0_1599670554813_0.1885167234749343"},"_hasShrinkwrap":false},"1.6.1-canary.1599849338.0":{"name":"@joist/component","version":"1.6.1-canary.1599849338.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599849338.0+73ef34e"},"gitHead":"73ef34ea55ac140161968e87cbdd028b49b421ce","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599849338.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-djKN1MCO40eRFlxnFAcq5q5ZuaqbDpASp1u6gzFu4x32so+wXnNur5ktonfb55EqnZnJFqXDPhhe7m7AguMYKQ==","shasum":"f262478a1859e2939da591270e6b1641672184eb","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599849338.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfW8OFCRA9TVsSAnZWagAA01QP/2Lm7rot22VVadawo3f+\ncL8SShCcaOtTEWjiwmgFA6bzHbXLXqab848wTTgXz+7DQ6UCEUjOjG268uXU\nJFFRsNaIjfPVA+zQAFk1BnbZyZTqB+HHfj8usOZfQyviO5SHcH3PppkPAMPe\nU3HXM9mrRrfMMkKl8jDsrOb4FKXx/ZqJXb4qLsHnjj5htbvQj7ab+QxHk3pF\nVzLyn5Z56PLlHltyYbSBAfr7vVjIj5HXipuz5aX1ghy8DppXFuR6fodouG8I\n+OgOw281hTZIBCxxFGozDamgVYsiz0hg8HOCPRrnXic5dhvAdrWJZTKL3IGE\naC4yq4gfIlh1Es1uQvRrn2I6QL1O3xvorIpE7ShRyn04NOLn3gp2CO6KQilr\nnBXOYJ6lFsrf3Y3DzbtzXYM1n3BGKQiNwmzJOQRWzlVBOZnnEghIG0JFALCS\ngL67Fe4fg1ROusmt7g5rwyH84HQkTKtG3Ze1lP8fPG/9ftoP84HAiuUWYX3e\noYrGH5BbBVqQhLeDrohsA8WwAJxqVuuYrY2ceqZ9TE8+BXiXbGr4p+vGvBX/\n8t8wv3ByWOP6NKYmKuCWTgFajZGCbC0Ec2SMhtClswhxPZUw4u4rNxuLDzNC\nMexKWlVvCe1Z/2pNc0m0cJ7L+AOtH2O5jgjBXGv5rso5gajCA6RvF1V2IHlg\nbete\r\n=gKFm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIGCGN20IfIrqTRHjrXDOdf472MyrEaKvMjWxHKRRxC0MAiEA94t1JpKyJQR9xAUaHZfIViF/MWXTUh20i2hOZnNA/2E="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599849338.0_1599849348796_0.619024240371367"},"_hasShrinkwrap":false},"1.6.1-canary.1599915801.0":{"name":"@joist/component","version":"1.6.1-canary.1599915801.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599915801.0+ee6382a"},"gitHead":"ee6382a4e6b80d6fd43829d66c31eb43afa449d3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599915801.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-PEPUXKthnUwzfvLzxVz22o4frwaDCOemPPgcaTP86LTKtGwi7lVe/3F+vby0ZaisnVQNNaKM3JMsNm+7z+8byQ==","shasum":"33056b16a382c21ec6a3e31d578deae873b8bea2","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599915801.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfXMciCRA9TVsSAnZWagAAwg4P/AxXQZTyS4gby0k0DrGx\na9tguEMBm1Sk7rzCwPxp4X4ZgVtzUkzp46onxuqfSbDTTHcRW08ApuFN7eT/\nlDWOKDX7mEGCw7IFyyTuTzMN/8lfhFI7qM+Hw3Crfj2v3sb+3kEdmAWJCrW+\nzj4flTxItnJjlH0S5WWkJc6Up1ejuD3WhMdLu7Y0PiIk/jtmvrbxemIlm3ar\niREgBiTMRp/5q1YmSAUz6Lfvln3TTmq+0kFzoA+pScMGpQk8//jAfNicV1hf\nbbO0d/iPfvqgalavGgJYSdZn7EX92ysI8BoYpR7Z2OHifdXpESeEG0YV3LY/\ngw2vQRRab94rt0V+Jevf/g5tPfQS4sWWrWUBxEvHON7xKA1wWjoUxLApumVZ\ne0AQ3ZihpEK8tyZiKh0zQ0jqmCQdv+5VSGFD1WUnDuVo0n38mXwRuqa3bYVx\nA4itJH1nRXm85eVBgm2F7gpJzfYQ2P2Gv48FPWj47TAiOSIsDLXKUm1rlZVQ\nFNiTe4Q0gu6hw5AVgVixBW63l85kcWOPaQRKtK+0ubWMt+3iZHrkQBxa3Clo\nTkdTcLI526Yal3jbhq7vmHG5tP7P8zUazEYmMcVLbjHSuhFgWj0V8epvizLV\nk8k6qiZlORHpxcC8/0o4w+LZPbtApSEngeCqwa04xWUCtjKvavvPwSRQdiPJ\ngJ33\r\n=B61l\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDbiF6/Sf9TvQWiFOQRkx3YaJnWRVvUaqY1Kkb7Ec2g9gIgG6OSSlnVkxT1DW8ofi/HJhB4ulqLtY9pFbK5YgQjjr4="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599915801.0_1599915809419_0.5549519573097552"},"_hasShrinkwrap":false},"1.6.1-canary.1599915979.0":{"name":"@joist/component","version":"1.6.1-canary.1599915979.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599915979.0+a7681a9"},"gitHead":"a7681a96d4926d4d1601c62c84d7656cd639c0b2","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599915979.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-JBCfjY0A8dEZdkoRSwKL7X7wf4uBlEl8GOiDAzJNckRsKHx6f5jRQO5hsu9YOygb/U9FgU6e/0TOFLxiDE/3Mw==","shasum":"daa9692571cc0d52d3d7366d3cc32ae627b3ccc4","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599915979.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfXMfWCRA9TVsSAnZWagAAk4EP/12LjonjppJKel7tpQKh\naFELnPrMbYID5ADOxB3z9Gke2ykL2x5eBb/q0zWWyD1sSF8eAPSje6APpFWe\nz3KXS9S3ykUBRjhmwgQ+weO3ZApXqPRCXp0NTwrLHJ8Wx+G4/V32zSH85+iA\ne6CPye1BWdKl4kDVJc9wdo8vWQWBVDl3UreOO6z/mNCCi66QPwDxniJB6Xbl\np3OyqnH+qjU2ft1xHqGKKnExNjGR/aAUTmVlyjL99hB+u7aiJpjxuMUA1XMN\nN7m49CXFBeTQxGhBLaAIjkpv93vkKypIQmYctL3D1rCL7Wj3+rD75+qEN51z\nuQc1+UpRjVKkruR2BuEdl9ALs+yQzGErtdQS3uhr4teHqXfVwovk3D9f0bn4\nE0Y5rrF1lQ8f8DEZzrZtdmvQBsQ5bgX7Y+mLw+KfN+w0rWr+bOAHbIec5RaH\ndlkIXuwfYe6J+ACTnGuIzkaxYTh2/WvxI6SVnGvEMI9Ujf2IKX77AWzc7Kbn\nTazoqGWFtuNzKi0QQGiqIFMxzGDTM3+6qqJkbOMyutB3XyfzYUWlTbrJjnXd\nWD6aBxicSPZJvCE4bAyDEx3R9Kan0ODKtHJ9rW1JjM3Cu7UiKrPp+TH6yAOD\nrBAdX0W1Ny/VWmmYgPILgRt36pQQW9c9WsfzbwBid1kVDCixHNyoBCCxUguN\nw7eT\r\n=rN20\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC66E5ciVzh/lNQB9MIIO60KKH3eMMRnm45o9AqqkychgIhAPjSxKSFsPrSoHmZNivXK7+S7pk7rWU83y+005quRClU"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599915979.0_1599915989766_0.8742809167008259"},"_hasShrinkwrap":false},"1.6.1-canary.1599997736.0":{"name":"@joist/component","version":"1.6.1-canary.1599997736.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1599997736.0+4a49140"},"gitHead":"4a49140efe73f510b12a12438a7c14a0f9b457d7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1599997736.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-awPYjNcqdtVAixMeUjixd/koqZ3rakdQQI7UtzNEZDzj2cZcwTC9z49vxg8yMq4Ou6as3i9Gru4RczMYZhrJgQ==","shasum":"e907a64b802f6922a4ac0abd6e1a8150e1f8f8a8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1599997736.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfXgcyCRA9TVsSAnZWagAAkkIQAJG7RE6DsA1YyEU8u0Zp\n4QSWANUU6khGMaAcUgLqIY1bRkeRpNTWYNInmhOIIP5jZa6/LstGXI5NozL3\nnYh5Am1SuwNNOT+/7Ad22kcOa1x+qpdVEMZJ/iTUii/s6keODEkLxggMtscF\nc8yzGJDW2wiPnrA97JEmhk4Xqs3juzwJxDHBoA005FuEw2WO+dALBHH1hDCN\nlSQdR0J4b1ZK5p3oyNX+9PXfppk+UPjYmivCqsZ7tr1XovpNuUEi9EZXrfyc\nC2BSj4DDhucsCs+aLzB1OREf4MfyUYbtuFPhnM70VdOEHWj3qQXhxzXAHxms\nwcg/r5+2NqkpR+Synhbn2lexwcy+mZhAqB1vv98v0lncZnxMWcmkzjC7/jIv\nESF/cF4SX6VULUTh+lJwFyj0VzJzgAl0rJd01qNUS8jGKcFtPI35DFpDFp++\nB+lU46CdCZuAXogBB6lvclr3sor2b9GyHMO7YOTiEkNu9xCXokvEMqL85CG8\nIb9daFTMCgXvlo1oUtAvKFAJZ7tETvQVOu2YANgQktp+hEmfrqyKnFy6XSCX\nnHjj7DTuCbVQzNh375qpCqEi6Dpcd3YAoj3L2cwn9rqmRHEFFasJKjv0ziie\nN9KZ/X1AEvvUHRnQrnR358hiDih/DLYJyJqkzUnUuhKSeLiaDfjp4e/oi9UU\nI09l\r\n=2vII\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCSd65viSvnnHsei6tPWEE9Uj2t8t9vnYrji8ChJv2zbgIhAMlCi8uzHkA8PbjUOS172W+MZXbLZgTF1btzaIP0QzU/"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1599997736.0_1599997746233_0.7309670220497739"},"_hasShrinkwrap":false},"1.6.1-canary.1600221675.0":{"name":"@joist/component","version":"1.6.1-canary.1600221675.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600221675.0+0d4c96f"},"gitHead":"0d4c96ff3dedd4f1c39a8833b700d3b7c5432e37","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600221675.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-DFm7DPpiFaA6fv3ZEyjb+ksnB/Icx7q+kTxcYzcM+aqhSrHfVOWlT/IO4IA4tZVJnAOd4+v9rpRA5BFW19F9fw==","shasum":"e7992f8cfa247109ecd05dabbe24c9e4d35c505a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600221675.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfYXH1CRA9TVsSAnZWagAAVPAP/37zPaQFEf2r3ufEuarb\nvmcgPMSIjwq2GHqOQPlIyEjVrXGXZRh1dVb25S2bPz7929aM0iGDUSLwxBp0\nzIXjKFDGvpI2OcXKndkFdo5/hFz7tlhL2juwaxr10+izV2aLIl0sAKdTQtb2\nAE8DpOzNPYLwbEbVnC6Ysut7JxWdlYI2FgeCsOPl8JR9r1ZmllWch/obVshk\nCEv6mlvc8BIA1b+RaFB9aRWp0IBJbPbSsdiQLjA5qJwwZgoH9c/c6kakqoSR\nE3Jvw5oX8/k3MuRXRLzUDJk7c4JPMRKhvaXHRuNQWUfhJ1QiHOK1wW6tyZyw\nXO1MgH97sNhAMIUNy+rtVhnQNGGp+PZ4gAm1STFwKPkVYo5iG+2fiAMAeZj1\nlgjeo670tZ7FgZtRL2cdANkSMSHGAhyGv2gFa1M659OKG+VN2jUOTNKQVo10\nCVTaJWFOY1EB3Kmmubd/h9wU8grNy4HBWOB75RbcXZLxP461fIfmiFVZ1Jsp\nxa0L69xCaAjrqRjDnSw2/YN9MtHY+/zVCTzDrYkokrJwHf2WARBWXT5yNDW7\nnsQvT0wCPbZVT6hgG/kkYoLZ4rZ9xZRS8Jh4scZbYEqwhCntJrvi8B4Bs8U/\nj3sPyWOi3WqUTQ26fJXlyY806+EpLj8kG/8dH9a0oAIGbNrP5IFSH3TYMuf0\nJGgy\r\n=gMbo\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCBXaurW946HprIY28jfx97dRCuO4mYWhqU8EN/iSmD+AIgAuJFnQe7/CAXDM6EJMZJHY61/YAog6xcALuBbAL9sd4="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600221675.0_1600221685105_0.7257173710378813"},"_hasShrinkwrap":false},"1.6.1-canary.1600258096.0":{"name":"@joist/component","version":"1.6.1-canary.1600258096.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600258096.0+ee2f73d"},"gitHead":"ee2f73d6854660f3e620b622af9fdf5a56dc6b18","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600258096.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-PaTPQcCdokJcrPv+A6tUXtORLk8Xncg+hZZyGzEAIKe4eiaLtG++Cp/weZSjXoRwh5blyNw3ZQnQmtdP96/68Q==","shasum":"e802db86b2e915605fe5ee701b76ea5fcf61250b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600258096.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfYgA6CRA9TVsSAnZWagAAbjIP/1z3p9uupVlyH1EHHQxE\nNK4h34hJ/QssRss2x4rJCvYO7k7ynF4+DIqYghJiOpU27F0SoSF0vP3H67jq\nBvDo1VeLN98BiBPHHmtM9WZS+AwIIzw9Ua6oDBzapY49ivo1uTfBKRATeKgQ\npmB/V9vCvNIxqIU+xga+alqlim7++wbxFxLGa8ffoFpI7ue4tzf8WbvLEY8T\nYv98NMF/9eHOrRqPombeKh9QFAByBIge3zOgLhRijbeUtCrNxhseIQbxvf2I\nRKvizCvO2ZUSYVbWO6fOCQBWkJ+MCGKgycI3pf7MNgxNlhzLsHuZC/RNXrDe\n1eBUhIckOk2OuNXGOCKJybFZlPImZYH0fpd9VMPXaIHWDn7s5d4hQylftSze\ncmBBG4Tck1d56gdcG6ES7BFv0Eh9HESphgjovOBC2O9c6+1tBYUKcARw3nyT\nipGOLTmBsW6WE/91ogqOiWvHAFp6c1Dv5UNfNeHME8Do0oaAWbBh6x4m3fYs\nh+W/4qIV9GWUbC+Ajb+VTcYj5zQEPCrtY38GhyL19u5jtLsktV0GVCtn+DH3\n21opAbs0aoksBkzHttn+s4fi7m8NkXZLUMmcbtQAckMpO2xvWwk/V8QK00jP\n+e6Ps2tzZuI2B6X6wfeIpwLtPm+wYTKdhlQWDkI+wQ6UoPS7Ak7841tJaE32\n2uYa\r\n=XChS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD4UhzkTqREm3tWBS3vXK9v7QmWutoMXX+9eAkxGseOjgIgXL1qdVJMT9/oNw9HUMwslvJw3caMZeq5bzLkGsnHSYY="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600258096.0_1600258105546_0.9193324215936538"},"_hasShrinkwrap":false},"1.6.1-canary.1600263267.0":{"name":"@joist/component","version":"1.6.1-canary.1600263267.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600263267.0+527ecc1"},"gitHead":"527ecc18ab8593dd0a9036ecf6aa69a9c75af7e9","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600263267.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-f1Huv/X9Y8iaNCcCIeoHvbH9YNmUKT9dkT+Cru8GQTZJ6qa93gFUWcqYbZANl/YWTT8wSpd/bXq6Fddtelz7kQ==","shasum":"2a0985c0cf593d780afc51a1d356bbc1d4b9d6d1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600263267.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfYhRsCRA9TVsSAnZWagAAJqgP/2AagBM/SyWqnHMJDKCL\nBPpxOAT/ZQy9aPFcjKVNOsjy9lxt5n3j6lt4ZuEs9SMQOqkt63EwJfFoHTf0\nLpdHSQNTgQVFMKlmpeAks8b5+D5i8EBgmSGszyi/SKvFrHbEGrIlorePtmXN\n8nByRzuTTJU4SqF8bFVgvmv1qazkPrcodEppg+Zs2FC7zB1tvNAesEOVsXOa\neH74It7+4R38sl0Pu69/Umdai0V1TfF0eOXIrB5iOO4Q0tPHyb5yULRCPYQK\nYGTroRBlvuTw15Yl3b7SU9CpVxQihD3KpsHie1SIEZkiKzg9pXLWXojnJJMC\nFgHo5nu8Zv6IfeeZ9RRM4WY0ShsIpO5jLV7bBAlyYtYPzOFqkgakKa7xXUZJ\nlA6rocd85CsEHfcR3vGeMDTX5t+hkzwVgg50Ivm8nV5r/G4ACoRXqM/GB75R\n73vkP3Vg5DBMDPz0k6LZL6wNwlDtsPk+TJbJ0ByWxb3UGepMUpzOldjonIDW\nj4879DHElUe41qqReSxL1RgOfxVqXxOLSdIW6E8xupX18jTxiUAN29Ide+oe\n7HvrqvFd18oC3xmmtNJFxozZirY0m5f+JO0NqHYqAMCNVNtZtLGDZ6PURKgN\nEX6dtbN/nNATbWoqz1wfZ//YYYfFx14ABTWKha8Hzvuld/yBjXoEy2wj3bZd\nN1EV\r\n=CH3U\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCJFddi0ddp5t0q2h9ff9heYnbCaxHDm3CJVBBSbD+UNgIhANAYf4RVyxKpAaL1N2AWAqtl+6dFwtbJ0mbozZNrHrIl"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600263267.0_1600263276424_0.451901817815894"},"_hasShrinkwrap":false},"1.6.1-canary.1600268818.0":{"name":"@joist/component","version":"1.6.1-canary.1600268818.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600268818.0+2d3ad2e"},"gitHead":"2d3ad2e1df8ca439eb589672657b0a5e752092a1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600268818.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-yBM69pzwWMynd+gRA5P6jc/k5v3MOwY+fvSs8nZCxYU/tODkmrrWNodra5vk/4gf+F5Bkte4jXJdYKcXJ33jMw==","shasum":"b59d2879c7d71ce7b65a5239bad64f5fbf2b7b01","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600268818.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfYiobCRA9TVsSAnZWagAA7UUP/2CrBJzheqRJdf2i4c4E\nLOD85edFIgk+UvZW0JSNy6RbmlDkayZUUlStPMUZcDV0Go0KF5KRGw3a26sn\nwLzhj8j1E/PACsFvl0+CWkPkv9DKXGOQuSNA5eIg6pnxk+ndfmpc0GaedNvB\nc8TnCNQrDQWVFFENSVRyi3bUNY7MD6IR2sqEQxRLLtfGtaGr/ubHhiPiXi9V\nX86mEJtHcSbRi7gjjZ6DplEbMfZIUlrgS3m3T0Qn26rgk53nt47Lk+NqRLnO\nMEw80skwMxO50vi2QkvE3aY333NONDKhZsWRHbocWQi1PPqBbLY/3PHZUC9E\naaoWY8zvww8TYXKmESWHv7koR+vmN21ntIH+mcAnUSWLUyes+0bBvp7bADAl\nr+7N25EZgGxv5J8FCncZ/53XJQZe+/isZC3WArxfT6Z3hte0hMMnqDWNRc+y\nQAI1fEpl5AKwKWfAit8Gim28COzO6z490GI+QrbalNf7eqeBfqqnhlm13gwV\nSnwAkLeUkIx4fOnhZ5gDNDjNnc3QBHejjmbTlrGjVjTWQldf77UguLENtSpd\neNBqJiKZmqqsPCr9aF7XbUy4EbAVF43HTTI89YMn9TDtL5xsk3qKPUF8jGJR\nuWTiHdawZmSv2j/zgE+2R2w50wuKPwt0Q7DfxbHeczfityBCMFv6IDxrxlRF\nxA+c\r\n=fG4q\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCm34869QQrqDev5mc7Cf0prtv3h7g3v3yEynAFQZleGQIgETN8JOJXe+A5pObdKKl+Gdh2t9EezhzcO+qOa77lVic="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600268818.0_1600268826737_0.4933657269271865"},"_hasShrinkwrap":false},"1.6.1-canary.1600293365.0":{"name":"@joist/component","version":"1.6.1-canary.1600293365.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600293365.0+894d3a2"},"gitHead":"894d3a20fa47962d07717015ff77c35dd4908862","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600293365.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-XEzhX5hmgYdPsHg5LiAslxn9PifyWODPj36EEHCxBIzVClnIXJ0GnKq+KuH54v/53088TcVs7dM5NsAxKluNuw==","shasum":"2922aeee7b5cdd6fe4930acb9b3e9cdb3c32d183","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600293365.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfYon/CRA9TVsSAnZWagAA/fwQAJlIRiis4H7J6mDng4iu\nmIq4sMv4oPZLAkU1f1uzm6xRNDKQMCJMtSRwvUBdyGQrAE6qszILio/vZcqA\n/YPDiM3HnWjeMY1Y+Xo8kt2XHJTe3/HDg8rZDpHwNRtKzL0oDcsFjGAtfddm\nZqpc+LijuzOgko+Q7e2C1CbhEUHk7iC+jBN3xnhEG1MrkKS7mzdDLXuAChTT\nLpJPSUXr9/FIOPIwmJviTaoPsYcJ30rWV7r0482hSwFwgNSxgB0BfVKsNd9s\n4uVFtMtVevfbtu7Kc1k+ex6oyUE3CEbBW3oi/fDDYZRs4mTfofYyk8vFues6\nvfn4BfzktT/UfMMhRilU+oWY8VWtaPf+2RBNZJK44H10NTkkaFiq5W7w7ait\n4rNWu9dBZdGNQtm3nWFSl7TF4SUPSSl2iEuv0thgWPs3R6FLclxe7ZIqZaJg\nMJWT/VxHRuR78/MpFF1OTWzBBRICB3kjIVCcr0ADZ2fNy4qG9MF8mAijmSd6\n9z54v6ZDZMGMYVVgJNwGNTkWp3KkdOL0kJRGYT9QYALS8rC7iMdo0yJ+ynYG\nD7h21kKCskHqDKyZqwgxRBdKU1WcJ969syArj+spSdcRmT3frN0Y7KL+rCn6\n1wzIz3K+jl7nyKZtPDYkZFbehYvzUUoPGVLnlDgXWjwFDxPKLnpfljMXcpJJ\nKP0h\r\n=nWjJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD7FzrrWLDFf/XlzxxpM7IQTbjWtjbtc4px0EuzD6PSVAIgBdv+5jj/WUjch7nZMwSH/37uVd5cFeAMGCSQ9fV/TXo="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600293365.0_1600293375335_0.1919974173715333"},"_hasShrinkwrap":false},"1.6.1-canary.1600344903.0":{"name":"@joist/component","version":"1.6.1-canary.1600344903.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600344903.0+bb5697f"},"gitHead":"bb5697fe6a0ef7c9cecf7f7f06304479646497df","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600344903.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-V+qWxob6w5Vq0I6ZJ0iDgi+uucgRyRc3o5adnvw3cBY+0G6cN0HdVvr5mFuvsGVk3r4WiHUlta19DNj0qT9vbQ==","shasum":"369985729170b784f2012459a299a347df579498","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600344903.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfY1NbCRA9TVsSAnZWagAAU5QP/iH/CYlZY6+KOUJq82VW\nkV6npXKCxmwuIg/NGywPWUbIHnBAbyqVx0VtHNG9vuLUVgHUh8kcuT9A44v1\nJZIuHGyB3nSrHe/GLewcR+MljRrJfEC1Nf0Sg710KnDdexhXw2D3/3ziQRRl\nWaIUjD8/imjErO2luJDo7/thyj8p5QCHVyUPTvdNvADMHs3u2Kt0HS+G+94p\nq2OCpUMNe0QMqBdf9pwUa1GL4jq5bImRohtyIxTxFNiAQMBoG9/iFWMQ1wLu\n/xuYIky2RoGWBCj1xeovOYMdokX+SwvPlfE3jfp+g5j6jWL9EilMLqfCigc2\nay/H4YXaX3j4wExcwqLF4ejJRGESF/y8xWZ3tjwaOXybPoHSVGBVhkz+EJ7b\nKSusJnkgGzEJdpOhW+L9uxVxsR3dHrdXuuedu42tFPKrNYdmFo+DvMijUzBz\ncNHBLUAFArvq/ZWgs2sDwB9hkz9h+mX/k6WbhJVVJeYAnkMpVayvUTaYRfyx\nfHA2oQ3so2wNnSOCX1XGW/fOfGBGGk60kBQNhPfgSy7xBtpyStmaUrPu1HDB\nZ53pP8ijCo5lWYpUB0RToIdTaq2BqtgfZTK7mP9hAKaKrafM8ncbsA4+BZWU\nwoeLLMgg4OY9/3/pMkJvQs+br+AoVey56UE2h0foHvrGmJ/CtIgROL1jpuxu\nl4nB\r\n=yXwW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF0aMnOz209JRPbc1Xlg80cIEOXINArWD2T7fqe8OseIAiEAm6zw8C6gJffXu3nibfkJIjenZOSwea0x7N8d2/PDGbc="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600344903.0_1600344918140_0.8578389563932063"},"_hasShrinkwrap":false},"1.6.1-canary.1600460240.0":{"name":"@joist/component","version":"1.6.1-canary.1600460240.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600460240.0+5654621"},"gitHead":"56546217563bb7c27d0416dac3eba78a430b89d6","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600460240.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-3g8LXGaysookrPKPuvIZpz2GvbB2kw8dll4tGuK0QXxDy5wOm7BASq7C8vRA8Jk3o4HyfzLLHA7P8QtgNJUB9Q==","shasum":"e4f9eccc55c28c23f017124697fd18a2d51957a4","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600460240.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfZRXaCRA9TVsSAnZWagAAhm0QAJfS+gjvcAsU1fVjvWNJ\ngoQxj4SWcM7Ibhkj5qAiHaIrZtG4wAw3SBICryVNDBh//XCjg5NvpoNfP9Z3\nlIBc4dNrSiQH4QLiNtmfz2YptDtZ78H0EFHw3FlZlR4cvDS7GKO340+Morax\nisM79srUfAamJ1p6bUbYpUrBBFzrLhvpmQpemCKdrOb/DVWyLyqZjD8BTKHU\nsoHqYF6R7YVUz6RogxR0GIi+DHtdKq6+9fe/V5YYiYTpTLfm9gA3uRRNABXk\ns4MScAukcvATakDkV8JqZAZe5fsRjbXfRQAqww4mMsCOjxFcgMWRjdMj15xY\nAAqQAtK/fP/uRVNkL5beizIjAISIgfgmIqxtLwoAf+vpVgc9/j+vmMDw3bW0\n1KDq2+XSqC1ICW9tB+2JPxbMkJYJJs2If3YFjt2i1uWWMup6V2k60sxNRrkp\nKozbys+O8TsbjIDTcCNUobm+lHf+wsf19Sg2ggm26sv6YM+9UgOzFUpgULXM\ntXQQR+3ZldA75oHIdTuflg1QSDsaNS634eBEFLg2A8Flp7EPaz7oxjd2FCVK\nke710bgrc/3gLfkRU8qgjkVGRB/njRvoKZvj7MCFGHjK7bfSEO8bM7rfPm82\nXjfsjJRyl2AG6mwkZx4AvnjrZ2ARxDRZz/KHYAt4TOmnnX8uP8UmvSyC30DZ\nt8xv\r\n=IGCg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDFDGaOZVOS/+qh0c5POS6gOVBlNaMuu3TmaVE8qW973wIgOgnMUtQCwkaNyvgVkyGWrF1FfIysLBFOG9WwOhjhzeQ="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600460240.0_1600460250318_0.5826699930106176"},"_hasShrinkwrap":false},"1.6.1-canary.1600515410.0":{"name":"@joist/component","version":"1.6.1-canary.1600515410.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600515410.0+ee9b206"},"gitHead":"ee9b206673fb5e25ec9ad53b64c19286d73037f3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600515410.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-CdcuON8/a4li5mYtGhYgb156O72lQ0gWsKYhW7neQeiRLw7DKOp9+eia1L1B8e5j9Lmn5tdRSRChoEKAlmcUNg==","shasum":"0d9a9139106b482eb093361459ee076f8be51077","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600515410.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfZe1cCRA9TVsSAnZWagAAkd0QAIxHVh0Aj1cvvC7ervUd\nKBE2GJ0aUa/PbQlyJtZVjaHk3kdPJIImx0L/YdmNEIxYydNFIuqGqpzkY6X7\neD4Zw0N8zJB6vnfxNtEACf9k/XGV5JQsGXsSNt0rh6SOc6d64Th0AGWeIMzx\niSbCMZmWWgGZRo9ACSfYJ2e0SEYWHBGO05Z29AMtdHpRVkDLgvpS10kJUPyX\nSXiIELOoSNflYf5C2a5pUpSA3vOMtinbo6WxZ6t/eii3vpXIaZRw21OD+pFx\n+dJcMFH8rsKagSns/t7A+tGDUYFrvnti7CDrhDPAAb3qDEFlJPbk2FISvLNB\nCjwU9UN7kQDuO6m4I1t9wK/aEiv9pG7Y1oKhClHSxGqo730iGbKNyZ/58ovT\nK6YeZqNicQOTYWvJwmQNWfYWw9k3fArmBTCEJZAv2WKOHtJ28ejvdv5uK/U3\nlnI5IqUUdA1Opyq13h7sB0R7hI5G5+F08ewt6nu6BNqPXN7qoraMUmzW4e/a\nl9VHdzravgj6LXtSXhSQ5mgM7pS12lhhtjG26PMGMDf8RhzikRzwZwoeRtXT\nK88IDN988epBNLoJvWz69TkBvInKwQrL58N25AVJz7IZULmznn5xyPlvuwK0\nlEsyUFSzkDvs1w8AhW4Jcy0R9NezrhtYQMAn/53MYQx1VVI596NcUnO9LzJN\n8BKv\r\n=ZAAD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIH7YSjTe4pjcA0PixzKRQN5MQ4TerwlEt5Zux4XehXSgAiAFxxoUJ/12Gt/sQl/Bt1fWftfMvG5qSi2YmhmrhsNXsQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600515410.0_1600515419828_0.7168211223276808"},"_hasShrinkwrap":false},"1.6.1-canary.1600520883.0":{"name":"@joist/component","version":"1.6.1-canary.1600520883.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600520883.0+8fe0882"},"gitHead":"8fe08822013315d9352146a04f3a397ed2f355e0","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600520883.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-I7cCT4Lx7mGwhmGZ/3+wNyapRuHqaOTPLulWzBt4i+GJ3swt6Ojl1v5Y8GVVLvdN6NK0nZR/gRfamqlln+JTsg==","shasum":"fe1e3ae47ee2bd727098e7810a7e1b3bd8051398","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600520883.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfZgK9CRA9TVsSAnZWagAAIQEP/1U4um0xTa8wdLucJfX/\nlU3ftvsIcDwKlrbmj9/2NieNDAqNF+0irx9XGRJ0gizc6xPnDIJvk4TKEDlN\nbs5QId14r+qStYe5og5IT6tW9Rlvtq86Cfk9RjSiVKck7pQx31CAoInQpftQ\nwBmJ964zAaLxmWic3jFlcGZ+wYxXSkUz/aAq0TB+yfYvs3QNPmuXfv6L3Lmi\nLTspSCDOZen0KgHnCUDXjPJoIdiSchIicWqd5cb3+nFkOuGPAz9V1okWRYJJ\nfzMIDBmHuZT5R7uPbo8zxV4Gs3XiB4uvFung5PKfeb/7WWwUhIKg1uum1r+k\nMZ2ZEfD5OXUiIW+vcND/1TrWm7Ej4GlMi26tucXVgjtxcOr6ZyOB9SKs7y0W\n/Wg0cd2hEX5V5CGJEGSF6TfM9R2KWN1dQdqFy1buRRznL7C8m+sPTLMaDD2j\nbH4bt4vPWxet+By4DjmnUZysHaFN/QGO44xpU7XPT5Pfx5xBhGmcbxxbe4dR\nIItKSRES96q1lELryxqil73QDzV0ZnisWu6MJb/ouMHrB4Wf02x7pj6zJcbv\n+Hfmp8z4kt+qv6mWDkvDBWxysHvMXQm9K9ItjAm6TkECiA0IV1vWy5z3a4rr\nTBoABFcdMObuLWAhacu4fsd4L7M1O3P5oq7dyv3mvxifBkqgYmbHWhrwQpjJ\na9Ys\r\n=QlpG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFHYEXj9YtXWoJf6B/tjRpdGJLY0OTQKcrmZTVYjS2nfAiEA8j9xMnd4Go0UjG1hfAcioR29sF/+7m4lEaaKRn07K6c="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600520883.0_1600520892774_0.4439727818207928"},"_hasShrinkwrap":false},"1.6.1-canary.1600691675.0":{"name":"@joist/component","version":"1.6.1-canary.1600691675.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600691675.0+fd9e2a5"},"gitHead":"fd9e2a5791eaf5da4a8e57639f3f99e17888f30c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600691675.0","_nodeVersion":"12.18.3","_npmVersion":"lerna/3.22.1/node@v12.18.3+x64 (linux)","dist":{"integrity":"sha512-y7VmkSM/WxyYc89LsR+cAnuaGJBq3l/dBCCLKuYmd5ZlBpzNcJ9UO+au9A8rb5P8tAMSiANZ3Adxs5DCDs84aw==","shasum":"461fc58b096054ccdee9e309fccbe54e7abdff7a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600691675.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfaJ3lCRA9TVsSAnZWagAAkdcP/0GGI1Aj42ZEZgb+sED2\n6qTOsgSJbFz+Plu7ucqZx5WZVv9J+onI4ZzCwRCmCxRTKPrU56Wsv+S/ZBkQ\n+A4wZ+26Q7bMlPBhMb0SGIjmFVhYPbqZL4c6159fGzA2Jvlqt0Gg73B5OfuN\nZgil+H7IngHSCrCut0P7cCA4ikOI/t35hMfKpR9RjWh0zYmcUKo+u9pnk8fk\njMLi5/jo3TjmKPIarCK3EsE/yGOearcCZtWzcxzp3T1Nf011tFY85Z4Tt0cX\n0jw0mE16nTHz6Za5FIHo84xGoAyMLaY7XD6htYs/8qiN+188jIGRK9krB6hK\nXaMkWiQz3Ehz8VvNnt+DKfVKfXlqbGni0XW3LMUiBl3O5IWQcQs0W04Lja22\nJqu0DqLoMob9VZIzSc2JjMTPd4JWhc8A0KEdYWMHQGyk6NpGabKdjyLiclIs\na2ltLaV3/b3UicAi3K1rWVoK7/+JeOZze9ozYGXPKQwEyw8RujVPruY/ngD7\ntw3u6XkaAjyY4xKlZqU4/XP5b86WnhN2QuNhas1kKuVnWStwxgv9y7YndUkv\n4QScwI36OVoKPZElZsYCzpxkLQYaZ1pSgY45Db2ahrgYuptSBKSIsyQidWMK\n0z+pa0c/7A8BWlS5xVIY9HYGu+2aDrBrQ5RzIqv0P60oxzboThRw9lGkG0PF\nelV2\r\n=680l\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC5D6PDMAaQwiQ1wS5O4E8ABX0/Y8cyQ+btxMlV3CnkpgIhAPI9r2Yio7vuZRgi+7kJvya+gd3mTU8Ndj4yrk6Ir9R/"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600691675.0_1600691685455_0.9519009951967152"},"_hasShrinkwrap":false},"1.6.1-canary.1600967979.0":{"name":"@joist/component","version":"1.6.1-canary.1600967979.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1600967979.0+8906d0d"},"gitHead":"8906d0d8346d15f9d07f5186dc4e009c467cf24c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1600967979.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-TjrUNWuQsPpCwQo8jBhbO5QOv6haJ1zYTJXk0F5+rdcZaYwNuOa/IhoNfto4RWywomt0/NCpk6c3ieLVo9h/wA==","shasum":"71ad15c34ff1c6a0bcb378a8a1b76838bb83a048","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1600967979.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbNU1CRA9TVsSAnZWagAALegP/142H20AtjD963KsFELz\nhvJOUxQM/i/xzf9cYthe7NHgsUmIyboWlJJhbd4UHoFteAvBMq2CfbyzDlRl\nrxC1E/Dti2OkwOMLx8mr3zTCpGqA5L+FunkGQRu9ynQz1F7FJOA/FMkk2LUv\n6bFK4fUtg0wFnu76WNwT8J/wcUzsh0JCUF1fF+Mm3VW0V7MbfIhDBzFZ5rEI\n7zKND/lFrmUmQ+Ez34HRevdrR+QIuJlC0swt0UaBGeZ93U5u0hlN29XZAXlx\nKNFukr3gBo5andKwpoFzL+gyOvswBD++RVqaix5KQ5J6yBaw1fHYE/xLeL40\nss0sziXXVDJT92jhJmfrsSTykjAhd6eImhxd/eaDTRv7F9tP1ZqFqVmzH2I4\nYBLPJglxR9eHveEmOlQh0o12nSH+uk1h7jfU494ICzXTRNkb1IEpRujmvaFL\nGPe3Bh4C2L7FAkD+yyzrYttbZjmYs+tUbTOgEtgzjc+WK+UYSv/yU6eHIAs9\nrLJcPNPjb3jIIJjZ5oNEpaoLoc2Gem4ZYF/kYMeiYjA9n4/b3ITTj1H/aIrX\n6XZGo00lDP+p7l5nJkKPxna+IFr6Oi9yrcMOnV7ey5oYqPoGBA8wD1gqs/p4\nVZWHaGy+Roi+izQwAtQ5oLuMYU0ptv4NPAbuXf3M9XsNXIZGnBMqSCduodz3\nywMZ\r\n=c0ZM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF5AoVHgHpaTNZL3074ZZVquk4oJLm7McBBohWyHycmDAiEA5HNkA4xBlsFag+R8S5a7CDSs65ML48jxx5r/cmMfAmE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1600967979.0_1600967988573_0.43431884567194734"},"_hasShrinkwrap":false},"1.6.1-canary.1601064146.0":{"name":"@joist/component","version":"1.6.1-canary.1601064146.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601064146.0+172fb63"},"gitHead":"172fb6368c2db963f80da2f4bf59fd6dd5374326","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601064146.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-rQwIsyubf5J1ge+cUFqd7q2/sVMotsw+tWI56QUHvxPQy4F2MhWEI63UaFirQt4GSqal5roFGWE6JQ3MRrAvBA==","shasum":"5db1c1c13ad5fd6e9ec0ad9b89cd8aa5b66706ae","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601064146.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbkzcCRA9TVsSAnZWagAARmsQAJuirU/EwkK/Tv3UnXK+\nQIX0MJEDfPyV/tSFflEciEj4l7AIr8Gjon1xFWI+j/Zvl7PXR6a08hFwpsmL\n0xoFDvqKSDYrgMtxBiJa7gIM4sS/dJ3/ULm/N79h3nZ+WSg8xxj74ZQi9me+\nDUsz6kSn1hj7H4rfI3USveOfPzH7lM6j4pcKsjBm4IB/1AXB/JYdL2pBVKNE\nc2JTyZwANwen1YxxHgccM8hFaIcnSuBd055GekJjS6UkULxxi10E7wL3cDYs\nfUUEURqcjbbsZRj3PjmDedDfi5RLEs1xyMSJwCSlVr0X6cP3qPssETcuJ41p\nbJXt6dDEKvo2xE3uSxMfEBtfK55xCGo0nq5Z6TYmWi6ZeiINPXVmcasau+UO\nkT5A/3ANb0z0vs0TAjhA/q32dCkl9Ogj/WcFTqj9Na8XfTm6YUrkcN10l38i\nlz4NZ8jtD07xPyh+WM+9Y6nGETDCNyD1JCKjxVt48ZlOGkW2ANvdVdx16Dbu\n6CRbIkSmiZVvEh4AeZhdMKqcUKR5XqGMkmsy/GKvsC2UHpYQS6QSdjZReZsu\nW30k+RExpTxyr9yHVd4BxcjYLHiaK/fi+e6YKMpgYM/OJzvj4mgT+hAfIlwQ\n7UoKnNARPNtIUD7li/WOu7ynfHtVIq470iH2dJcv6TI1n4yhJM28/Dn6Ksnq\nC3h9\r\n=l9Ac\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIF8f32hh3V5Up3eRPc0SJXi184YigkgPphAycZrU6m0IAiEA/1tXey4WijpPnpbzXT+h7xtlXObNKP40AFv+Tw86Bwg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601064146.0_1601064156205_0.7467789157335523"},"_hasShrinkwrap":false},"1.6.1-canary.1601064148.0":{"name":"@joist/component","version":"1.6.1-canary.1601064148.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601064148.0+243bdc5"},"gitHead":"243bdc53bffcf1f9046d39786717ccbe7ad79543","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601064148.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-1LH7oetbB4mkBoyw01jdPfrJsxakfctqcZnJYzTX6cKw12jPRKuGD5xYkncyqcfuMW16HSYQZdBG759g6mSUrA==","shasum":"c47829fbb32a9c4486854a5c6ab42600b40fb024","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601064148.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbkztCRA9TVsSAnZWagAAEKAQAI+EQ/3wQP/eiRJw+9G5\n6YgyjGFApVbnUj8Il4AF6aaZc3Ychx+vGG2t4aaUAu+U5Tt95eE7oOEuz83U\nE5V+EqbAT8F2KLV3azyjOc3hOI7HDwQBvpAuuPaUOo/uvbbpKcjNrWvkbNXz\nyUUCybdaXFQo4X3zTqP3/5mcQhaYtnbVtft62a7K1nVfX5T8Hj4OS2im5rkS\nFlvznHCUog9OT4xT2xMhGR6Xhe0tXKcHbIBIq+yKcQaMEY03EvgX0206iGwD\nyp84KNl8xkSmBtZaraflUrzN5KUOhjgH79bCWocyRlXtOKoLz6tSQyqLecaM\nmx+KKZ2tFB2lvgcu7qjw8nEZmW3hba3j1Y1B8rhHA6x5Fsr6LZEUOW8Ti6Lh\nkkZkMwBYy7tyiWtvQ0H1QPawMbJHtSxUaGSJJs6PfnD9aO0tVC4HiwziQo0K\nnQ5n46/i331fRoZsxr+dWmEmSbxv6MY3R44EvX1fGQ44NXS67VEkf/7Eokqd\nm54OpM7mAfbGy3jjK2XqaIUjHR3HiKcutI9voWGjrjakSsB6lyPUMwBn59tP\nhGUQLLINlaCLyeoPl/pd/zEj3XiFiEAjIhZ2BxgvVVJis3EIeM+Bc/JJdmV4\nuIjYTlse5XLtdXE+ahFxz2GBRY86ZKJfwcEaRXkWAKJ33uf5yxeHziwG+/wB\nG75+\r\n=QwAl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCkX81xldlz/r5SHRtOTDI8n0LC6oRYqKKDV3yzwxKMQQIhAMMHY1YCilVXr1wBw2VCctoIsxFSnYwbmLTRhtVaEo1U"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601064148.0_1601064172501_0.8037642118567108"},"_hasShrinkwrap":false},"1.6.1-canary.1601070741.0":{"name":"@joist/component","version":"1.6.1-canary.1601070741.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601070741.0+d0c1c90"},"gitHead":"d0c1c90c248433555d82c6b1857ff738a4c37fde","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601070741.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-8FITejBI3VF2RTKH2EkZDDmiPpP94QOu1TnwhpFZgRRANq6w8JsFobTakYiTxLl1QkuAMQINn+CbLgYl+sdObQ==","shasum":"311a9dd2ac15b881e3e13332197e55ed3e7eca68","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601070741.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfbmagCRA9TVsSAnZWagAAcXMP/177SyXEtkjZPMg4oPHw\nhzcK0HyYItjeWSZkQcXJsmFH8wYFlKarZh/KydiRlMJaPkWG0m0LgFmrqbgF\nxn08e+sK2rghYJXshVa36pRiyC919DcuYE9GHBl0BHeAKpQSrWswSflhGq4E\no+E9Xwku87rV4b3Px/zBWCqcGdpfri96m9KKRN4MXMgLcxqL+1ZJTTNzYzBY\nHD3hYYZXNYmtwqgQApIxkMXahTmu3x3JEPTi4+v54FgMvbtue2ZWrNtqfVLs\nwPnbrqb8qQmn+8Hh125Se+R0XWz2949GoApGL9hyaDYouyT8DsKCGfOb85Br\nhRH0vuvJRDjR4nso/9A91qMCuEEsu7EvxdqQhQJOlBZLZ5oPspiXqvLTE/n+\nzyhibi0dk+c7XRbd1vPuK3c47x+RJlMMLac5Wox7jO5WMRgZ4SyWOFfb/yBZ\nobRz+icP5zSrY3RQ/PEGSp/8BVsMmLon1MtVVIXH51a04TlnUzi/4Zl728a+\n421hMIGgN+gpz/81hRv8LTrxX2HgDmqACpjLsdQt6Zf5a/xW0xSRYM7zobJn\n6/nk/EnAfyn8t7xBMW562r5niq6lSLDe2BuWqGJ1M8dnDXfvApvxgx+LR+An\nNl64xTBVBUOqXyOzuPI6I93PquDOAQ2TucY1LWGZJLtTDP6jkvXxvXbOtmEI\nahAL\r\n=CbNk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC0r9tddh32dP1+fqUC4fdh0sS0wR8NbWm3etErM9uhpAiEA5fmCuc4askFDFI/6OuCWgbxB6CyoQfwhqPd7FoaptJ8="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601070741.0_1601070751551_0.056298795892281595"},"_hasShrinkwrap":false},"1.6.1-canary.1601155745.0":{"name":"@joist/component","version":"1.6.1-canary.1601155745.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601155745.0+8fb3dd8"},"gitHead":"8fb3dd83197eb80d0b025d05224b12526d4952c3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601155745.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-Nxs7jfDeEmQ4Ui/kpRkjARCKWLcH2jwwWP21xIj9fxwvASbVKOC8am15nTC4yE6tSGpG6rlPes7E8TOUDC6MFA==","shasum":"87114ab8a8c0be52d1abcbe665af0ed8c919b6b5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601155745.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfb7KsCRA9TVsSAnZWagAAx9EP/3H6hIwAMgB7k1u90pCX\nwwoFDwTr97RD15pcTqs14a9JNl9ttQKZu96kcCrclpUmQKTOOgc6mFI9PR6Z\nAFcVL9cUxCQ3XK2Xgsl4dmenrIHEPfNB+GFpTSoq/NH/jds2DbJg7rK07UUu\nZ6dz78MiTF5tohAjckrK4K4Z3W+6fpt3PfnW1Uue86Bbrz9MBRezk3YCEUK9\nH3LyDdqAa9qnL12q5kP5FAHhR7oKhEZyWIrcZtzJAj169Tsm1ILS8JH+0XW1\nsQnHBCRO1G4wkgpE7JrpWLDVxK91DaDHXp2Oqj0riPad3KRvl1rf+KOn18+h\nhwzrfrg7pf74qnEkH6HzYHqt23WF0pV5hqPpqcZYvYvbp6m1LQ22RGrjAxKK\nOtxuEjyhvHoG2MdRhly8JHFeJbIq0GjDGdJG3rz+9OM9YJSZGjzXC2/+qDzR\nPcV7PRVPOcT0aHmS/bh8+O4tl3iFRtoPF5yAt/POrNHEmpcqIP0tpSCIgMXL\nSO6lgsoGnNkQFKEa4JOcbbyg/PzqXLHDdDiU1G4LH0SwgoZXslGIompJeabt\nJcM4WvS8VZkZevMBRJYVnVgZuqV3bxRlwRGPRTk2K0U+WSJIuu3ntvbwJwyU\n8f4at2TJkz605ABi+jslJXgdf1JLknzrcAdVoLaoiHTKnb+H2HkOHpaSAIbr\n7RZw\r\n=onrM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICHj7tCeI0O6dB2bRtr0Sz98R/71el67SLExtmWN4A7WAiBBHoh00EpZPi3Ra1Bk7IPddhPQgpBfDLN2rh/dcO2ToQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601155745.0_1601155756265_0.5661096425015859"},"_hasShrinkwrap":false},"1.6.1-canary.1601215868.0":{"name":"@joist/component","version":"1.6.1-canary.1601215868.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601215868.0+b63e878"},"gitHead":"b63e878fb85fc8cc5b89605ba3526645038eefe6","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601215868.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-F7QRGLdkwJWKomW0HSpJ6DxpJuYMEcXpRr/FMf2oAbWqk/EfVYjEhamhjldjQNqYjqV23kGQ3rlQnF13x6hbRQ==","shasum":"5f73d0a28bde29b1da850e34b21fa86b2b8d4231","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601215868.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfcJ2FCRA9TVsSAnZWagAA4IYP/i1e4BacRdYFcvkJysC+\nfAcMTJIZlyBQLuKpw4kNl98StwsLl0TRbaRIDGqk1SZIbxeSRqvlNAzIIqjH\nauV4WwhJCsk15ZWvztTW9PImDWemMnD6mJp2fy+WLojQ+bHuyTxvsxGJ26+f\nzttLszChN0fJFKZnv14sZ+8ksWod4jWINlSeqOnzSoYbkGxc+OJ6gODgS96C\npyHXHJyaqN2mPLPEArLwGphIxntgBMJ2jhbLkD+IG/S7xTfZw0PQUIaJE6Kv\n/547RJu+xoTXO3be2W86DCKj2ldyngDYUhBZsp563/kK46mw95M6K71Sj49o\nDz6TCAWW2bZRAe5BcKOYw3KGBmoNgf7y5vC1sG61XFjreKmbA2HJAzjq1ccj\nnvTXxlVpppPNrh+4z/k4/NK0hlC2YPnipiFWf/nGT+3H8eeXschAV45gJJcY\neu7foaOhwoc5mUiawWmbLYF00M6q/J1FX5MEawQJUX75Sqo+/bBjXyPWmscM\nQDZxnKb4jycamaTCpdOvrPg3KNnWfnVz7Gnu9cgjyEbbYd/JK90H4R8j7tKm\nvF0Z+TJOWAaY+qn62szJsI9Ra8VvoE/1/5dcT3g5ZybIZL8NHEcGpkPTGGX0\nbX4L3/ghsi0AS85RQw0oTf4V3qT6MvT3RvMpzwFX3S5PRKZHgZ6rQlxD6QzX\nDUpN\r\n=7kg/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHA8WwchpQynhyzWEag93PD8P0FMil1laikF9jvBdq4HAiEAiaDy+yazzmovnTRuV2Uigokz1M+v0p7Np7ps6IG3o4M="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601215868.0_1601215876837_0.41182501298342133"},"_hasShrinkwrap":false},"1.6.1-canary.1601349632.0":{"name":"@joist/component","version":"1.6.1-canary.1601349632.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601349632.0+876e96b"},"gitHead":"876e96be3cac13f259f008aee97f73b3a2a7377e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601349632.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-+hx2d5/rlPNlZwSL23OSL10Hn+5FQYedXA8NzxvV7JqXOQ+rrcN6cVjtVPTxlQNQ9C6c3hdUEHoJ4/YsNyDWfQ==","shasum":"6543a74b7d83982bdfd8fdfd84ae97ddc70e8ab6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601349632.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfcqgJCRA9TVsSAnZWagAA0NsP/juAkctYqlWOL8Dy3XPZ\nkkfmvz0N6us8VsTvhEE5fQKhFgmIY0NRxtqmIJjcO7TCuQKmg5EK4d4GT6Ct\nx8lQ6SKPHNhWWzZ4Ta4f03u6Nlvyo/JhR8L5wvA1rYlsfoi7aGcgkULZlbm8\nTrCJM5+FE7uX2y/dSAhGlVpSkFXjbxQSMrlbfCqUOPTyO9XXUlmLMX/OPqcd\nDm+GTMtdqtmI1tOaxL2CTEU3q1nKWY2DHD/OJedKjrUCmvq2w++9fV/Fz/k7\nE7QX8PiOmhLsH1gbIYYcRjFAV/FWpE4vPjumnFFGis1y3KRwIrb5jr6yHKFQ\nZPGCR0T1fY3aV9ggm6kVxZteiSVAoOnYFI1gtejvn+cUGycJQpYfyUf3PReG\n8tggRRAKEMdgZxSwjxShnQ9AKWnWncAD+WhoWI7uZznuTc9jqoJ6yuXnCI6W\nQ5p55yuJrdKtPkBgBac3bXX8S/wuPcvKLTGA4tuDoOYVqLB6djLu5ioh7ggB\n/jfd7eQ6+oayo931w3h9hPGZ82iINy0RSVqxrpAyVKM6XYNNRMZp5ZoLHUL7\n1SPX693ZagTmnd0tIQ10+yUYASMKusoarLl0CqTZr1lHRDdHKFalIVWT+E4I\nMD1IOSR+XqdrAgiogE1TcMQ2tyhUXTB/bNIDiuJauYu1pCjB5qz+tLVwBPum\nnwJT\r\n=pvOt\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICfyft8VCHJoly8cEFrb5X/TD8VPgeJLEpMqGt5gE8NRAiEAjGoG90W/gq4HHOW7zKqF0ySY2J6tvWtFTPX8y7fKcq0="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601349632.0_1601349641226_0.13729789613002508"},"_hasShrinkwrap":false},"1.6.1-canary.1601409860.0":{"name":"@joist/component","version":"1.6.1-canary.1601409860.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601409860.0+e1fef83"},"gitHead":"e1fef8381d18906a301c00a1a13d809ba18242a2","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601409860.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-wX+TkgTjdRLEgocgvDNz9ctlXwa9Q1oKV9zEqlc8yFodokSP9RABzfqt+AyydcSGmMXlFv4/5sYkRkc0PORabA==","shasum":"679a715d03bbb9a199c2f35b11222da6a2d71113","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601409860.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfc5NPCRA9TVsSAnZWagAAM3wP/Apiz8+FQpiSBoal5WkP\n4ANIh4x6dQfAf/H6EX6CaUnXHFJjG2qPYka0Nw9tryMdsrAoEkBl6mKB78qe\nf/kIFbHygMWrKKLlRw+jtdlnxSlb8stp3hsUJHSKzdTsklFwB09WTxFdMgtj\nRnZwbTVGduAhQkDVXarLTfb6ZM2WOcSOZPfsAJwv49EGlzqSD/s2N99YdfOh\nDf+1VSTEjerE8RyEuipiXWiE3YYFjA6GxnAP3OiuEsUsGVOtwwX7WclIkCEm\n8qZqVTZYC+zTlxmbJPW+dHER4HB69Z6aHAthPbnJ54LBRFkm2dNUC6Ts2mf3\nlzWv/9bAUg8pr4hse+qk4ZVSoF1DNJsVDbaQ5YDyMQFhT9oNV7gCLBzqNqHz\nXcjIh9XwJy0Uu0/f3UOmE0aDtzL9MyiZ6gFZqEc0FQmXKz0KySizvNZMfW/m\nXqgLZ68WM/R2vsgg5r9trEqRzkGgstWv1vMgMN93lrK0LF0Q88yW+xKCQ8jq\nxqxSsq3RyA6Y+2CNAWZAwO/LMJv1Gf3AOVrJQxqcNQMT8LjwaQd1Xza6j/ho\nJRa0QP7iEblpB0ki9g8+nACmM8p8Qo2A5d5vbVQJKr7xqBJnarXHrPfbcfTf\nLj7b99SWJHZ5tSeJ+yIque1YJtD2WHDAvfyTKmF6XYuwAi216aWXhXCVeV3M\ntE3d\r\n=vuoB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCuUDB/xI+wswty69VMh1n3zlzc/R2GbvjWjASt3R12lQIhAOOr0lM8kQVgvWhjgfg5FqcxNl86mK+cHnyZ5KLhXj1x"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601409860.0_1601409870492_0.7972195997806975"},"_hasShrinkwrap":false},"1.6.1-canary.1601424284.0":{"name":"@joist/component","version":"1.6.1-canary.1601424284.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601424284.0+d7e531f"},"gitHead":"d7e531f21a6b6e7d703493755d905d742ea8b89d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601424284.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-9gxpoc1/xrJ/UXpzWVzCA3TjwxBNhPw4vmFSgodBxs4SDAlhESfnToURScllfrqsEFtpDCT1MazZnF9mdItyNg==","shasum":"ff4e6f96a93fa79676118a0ed9fe43ab354e33d5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601424284.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfc8unCRA9TVsSAnZWagAAUlAP/2r0QMcvKlqyENfD6aTe\nX9fGwikOxEsZqle2FholYZs/HLipXnfHElVufaa8jZGY5gdwYBNrnbLk0I5m\nDstm5FdUNfAhO+xc9yLi8X+gTxLejD5JIFCR51yQNlw06HrKDB8OKFC0yZDH\nJeKN3mIA91h+CqUrM+F6LxnXj9OHwuHhwX4Okw8GQXMjZBoAmGO5CmGESu1e\nj/0m3fgEcdT7Txe+wN3XMjB4Fa89zD+wIlBzNEgkHDfqNikBRGoMobVsm74A\ntpOp9XwgpBnukdJ1zQyloucXlwDB/0iJSrOOq4u4zu9I2wypAD5iLRHsgxdF\nL4nHzdJIgVsliWAITQ8YPsJNEYCdIwYnjspdw+vfmsjlI7IiqLVZgrr9Q6nW\nWhWGpK+zoRFvxQJhAmMGLN2sGRGfTWL1lXdGAijI9a2qyqpnzEvBz2aKz/J4\nw+/ITSXEbMtbi6u5MQxaztJ/bwhobEmfa+L6BR1XEzFJ9bJWgc8euaMD2MfR\ngsCHm+0Ig+AjFUYkTjpdBRLlQXrelu+fn5qtoC+YfByS2sIbzVrcYPBTdZWR\n0O94IWSChH29HCSzd9R/kQ8pGAfI3h5muTx9PdPRoGnMbDbQJ6nr6yQ7dmBI\nqVmVe8Ciejpzae6+bHnEK5E05+Vz9CZ4TVuBp0qZiuANkm6asdIjyCuxgxgz\nuk7n\r\n=UxTm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC5llppJYN06RqrVtVpoeMBwtveVNsWoUpKyDduSnWWPAiAlNIIkF5yPn/gDGd+FRbbbndfHEP7ldZZBipY1N6bqhg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601424284.0_1601424294593_0.356117332084531"},"_hasShrinkwrap":false},"1.6.1-canary.1601424292.0":{"name":"@joist/component","version":"1.6.1-canary.1601424292.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601424292.0+8534e10"},"gitHead":"8534e109e9be50e391633c0aff8fda1b0c790c90","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601424292.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-mu4RjmmMfwyI86LhwfeROoZ5oFKG1+32BCF2qFhRVjQrLhcbpBhB7Ufgg3PuDyxoLcA2++vBPZ494qp7+N8Hvw==","shasum":"c7f71e16c2a92cc62eb9773e7c6fc0c3d61933fe","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601424292.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfc8uuCRA9TVsSAnZWagAA5S4P/R9fGH73BXwLLb6UKqJx\nCu7AS+FjyywJPvM+WwW8DBHZ2ngYxeDDodqQOu5GzTRPUwOZc9xTSlzM8S1M\nLTuxvjRj5MStoNwsS3bODRwPUe7qSu7T2OfWJZ9K5FtnbG+rsfv/HbWeaiN7\nnDVJdTodJIYbYz0Pi6D7Tqi2hTSLyU6OO6T3zBEwVM9gYyH9oxxYUDp3x+eL\nR6A7B6VjSr1XpMlYdOeyEN00EIBGItz2Fe4TC3lLbMjT/pSkTyknj0K3I9S6\njU5UgRbuOTiwS2QeZYOcmAzJ2OGyw7RVnic9lKuCPkCmgq0UXnaK7DZxhmry\ne66R5FeQiklA62qJZvI/9sW4hmOVnVus2jhe501OEzCblMchlynM57yhoT7m\n0YcMG7SXSChJnFJxiWvMJ4vqn90qfxPWnR/yy4pN8OGBXHuu1aesegDQLs2M\n/jMzZylg6JneB87pwfNA1fgY/xQsP0gfLadm0DlvF34yAu7RvVBxIVbD9NEO\niWp3bgJD9Rtm+ZsKjXmRfvNNMJ2uBLZJnZAWOHKNJ9Bt6x/2yFkFkRM+sivM\npXplDMxvQm3cB93IoYHVGAYa02edVOeNgCCxFAo/sLlzyLMfhkuHXxWyK9A/\nb7HrLNVF/FKsTGXWJD2sCri6qDG4IQkzko16GdWVZKPFdPD2w7OMrg3Ck/MO\nq3P9\r\n=2Zpw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCgtL/+cc8EVaSNDqPtjnU3Pv2wR00OrehdXvVYW62ItAIhANw+dLYao9fzPIxsQiSpDiq+XNIPSFqfw4wh0D7HHVUn"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601424292.0_1601424302191_0.13927693111883932"},"_hasShrinkwrap":false},"1.6.1-canary.1601497934.0":{"name":"@joist/component","version":"1.6.1-canary.1601497934.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601497934.0+6da9ce9"},"gitHead":"6da9ce97f22ae24fb12735d9d6ca9f9382e59e30","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601497934.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-ok8fQfEzqI1V0x7T9zcQ2ClKo9/UQ7bk5T/tHpgPDjv/FyeCuHAnTubng4IpO+us73R43mp/wB0o7Yc2by9l3g==","shasum":"2e93f522e6a2b9f26616d3571a8a5caefdf74ddf","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601497934.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfdOtZCRA9TVsSAnZWagAANVcP/3RT7Db7Qgvsapaf+v8n\nDupepsrmlxlfKX2NkSEf0r5jyLbwutPN5vDYo+wdamK0dt7oIks1GQyC5rot\nIrnq1lQWDPgyLtEYKqkOR6sIJDmcF+ARdG8j/A9zUE0OwvowRvybCE6x+wEI\nOrzfNBIhI5PPN0wo5Ayfcik+/WefqFHbnQ1bKrVy5ycN2iaSmb1vXl20Ce0c\ntVzvvvtFN0aKo+6TtVMidSkvh2jC8DWIJZniYFAsUJfTJErz2ZrGFF2MrIqe\nwntox39iTQzXc3jq9GOWTJpKTWcmsWVcz5oGCZ1LRKDX+inh3c6PyGY1FJgq\n65ZsqTA2TwGRRl37DgpNvwpDbygNkKOcqacgg0v2Cu/j3yUjtHgbfMSXr3ta\nmSlMmhxQIGGXRx0XGALFSjppneyKLPSecci4nJxYk+Jgt8JF+rjTon8VJxV8\nVOvkZ2J1a1qaz2Pg/n8+z5HV0zv/P2j032Sj6hm0GMyl+dFn57SrgQBIXglo\nchf+Otxo0K64beExEeXmeuYw7+mTDAi/Pgk2H2zOvWn3dQNlU5flZeOlvYbU\nEHogcEPNY7KiI5tPCuHcvZUvBaMa7fIhTkO0UpvjzQO4CmaJIjA0kGctTHAN\nZvo25DkJhbivbVRh2ajj20J+f7uae72ZzhXUXFajpgBHnDstgPuF9zNDQSMD\nPHjZ\r\n=Ntzm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDjJvt4I2Bq6pT+Nyhvt04fFbLVWLkBaXh++o0yYcuywAIhAJEu/e7P4286Vw9wFZagoW4afNrP5h7Y4OTPZMo27cus"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601497934.0_1601497944992_0.3867626418508632"},"_hasShrinkwrap":false},"1.6.1-canary.1601514866.0":{"name":"@joist/component","version":"1.6.1-canary.1601514866.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601514866.0+3a10fbe"},"gitHead":"3a10fbe82a8d3d196d522eb105136d611aa6f48b","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601514866.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-O/lBTCTIYB8uB0FQGSgvp5F83v9A8GbDMF+uZtujrdcP/tGoSJmoYrKtKRgcaYSh5aWi9MuF/p/zycOrDlXmyA==","shasum":"ad36e389d4ab779ec8ddcd1f2650effcbb8540c3","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601514866.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfdS19CRA9TVsSAnZWagAAn/AP/3cnTqss6uPkUk+uK9v3\nxxdfmh1cpqsHjOwZOJJrhhURqZJpv5yWmPuPD2MMwCuvCSYizEdNeiu7H7g0\ntCUqB+iOKqOBjDDtdj4V1kKGqex7a1mcT4ddq2Ad8kuAAnouvW7YYynnZmlI\nE9bBx/ErrEi+XPvTMIUnkAmOmBXnzEM73n4P5eJd/vcq9g57bnMEDqDmE5zK\nzoUuDEnnX2nNB0G7vdfEv5wzBIkjeOcH0Z+8K0/CE/vBgRn+HY3ZBzyEirhQ\nFkRAoZRBcXORYP6VJYdb1w+sfcLIV902NwyESjyvEiyGeoPXY9Aw2Tf3RzNK\n9uLfFQevky3WDwHajcmhiXYtiF9LDNHa07Cq/9ZVAtaeP0gE8Y4XocfUmLm5\nRa0FB+3Lvum379caI4I4DYFUMEa2fpN3+AUmQ12tj6/nnmFwN7H/2BFzsce9\nGxgejZ1dfhZNvT1UWnlGYRdMaF5vNfmEX+dbljDvsG4KmlUuMc8FI2PXAQJM\narPo3pFq7FezS6qNzDIBKlu0yVFmZNoE4Fl7gnxFtuda1Yzc553UWRi3HSRr\npB4SQUlxwf/67GBGG9jrzZVASPuhxAez6yqaGkhjuHEQ2uTVEIq0cidgIoGJ\n+UeHDkCXRD3oAqMfbct93UuiDa5ewApdFOJ+J5JS7mvERACJRF7riLeFUnMz\nVb9G\r\n=nfyb\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDeFmn5TQ/vPRMFGME+EBTcJlHfCo5RU6faf9f79NQhvAiB/RBh/FN1asUaQZUXXxb2zqw6rOlb6NnNT7Fok4MsKgw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601514866.0_1601514876693_0.4848277430298489"},"_hasShrinkwrap":false},"1.6.1-canary.1601576242.0":{"name":"@joist/component","version":"1.6.1-canary.1601576242.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601576242.0+1a1127d"},"gitHead":"1a1127d5d51020183ae23e6469b788d21a6b257c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601576242.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-f0EfwAJOQmGzo3FT02ciY29S0lBH8groJnKSzRkQCPY/nJc4Lp1CMoQPypiBOP8XhV1JZC2X7YtuTkZsWopQiA==","shasum":"2001a2c7fab96b1479a35f3d25df7341aa2f8628","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601576242.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfdh07CRA9TVsSAnZWagAAuWYP+we7X3rj9aSjl7ev+ebr\n9acT+i29kUDjHGi2dk1+w/s4WW/RAV+7Y0K+leEvIMO4ymkMW6SRYT8ZIcjo\nr/nxjqQSEAEMMNl7a+Gnks7yzVKOnwwhzPLoacdNp+ie3C4lLBOtBR4tq2U4\n9WmSw9agqM1PBsFzdQGl2TPzplpYddI6Ldj4N/AJpJTlXfLvKQk5w5WRcoaJ\nSv9Uonu7Ox7ORwDjdy3WgnxFb4GVt+RZtkh+Do7H+pJhAs23jPfxeuS5Zdd2\n6U4ULalN5IYRMOzgkRQSlFE4xKFGj7Ra//TE7stYtAo20mkljDIjhUFszEaK\nhg1DO+HbK3RWzOTscVz3DuTstOC9Mbx2zEe9ApvMs1Wbb1BsgaOVYZYc+GRS\nYz0457WwK6DnIIR36oupvpw0TTc+C6rAru005aNU4gud3u4XE5h/mBSHDP8D\nDuxGKN8CGZ0fBjOA7gqJY6puDJyCKOhvJWSVW00JhN1T+Lde2kXthDLj+TJx\neg8xnjsBV4kW7xnYuB++VMqp1Y8Z3dOXgb/CzHjapzxJ68aoZ2duOHGK5bPu\nZ08GtmS82xo/9h1tPBJNbRU8umNoPCw9ZVYNmqBe6938kPEJHM/M/3Iqpj5S\nGEZoRwqCG2rYtHXjULGmDBY5Gl6QpVezcO+LDLYnavTjEz6JVM6Vtq74a2Nd\nNyZ0\r\n=VVEr\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCbaS0MamyWu7ylqifJ5skyH493UTUW+55HbZTVkkphtwIgPdqyMbdXxU4YB4PTE4iumtFdNFUHcjOi5shW1qo0iAQ="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601576242.0_1601576251342_0.017525100925721127"},"_hasShrinkwrap":false},"1.6.1-canary.1601680608.0":{"name":"@joist/component","version":"1.6.1-canary.1601680608.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601680608.0+d4143a8"},"gitHead":"d4143a808e87f2b174e350f5276b2c437f13eb79","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601680608.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-tM8XdXpKQWtP9VDB4ZvzWD9x6ItoETrytWgpWc/Sbrb8wRtTQeoSnYNC0Yk2cP7oPKR+CXQIz40bnJvOtxxSSQ==","shasum":"0794ded1d6353288474253b730fbf5019780fddb","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601680608.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfd7TrCRA9TVsSAnZWagAAxAAP/0wTbsVACcMSyKUMOYeq\nyQvWogb5a52i9dD7tShCfCXLu3E27XB2HQN0tVI23uA7iN7xQ7yCap575MGc\nyWW+k09t8km05vvpP0u/ZOJX7RqsoSTezEj2jWiwtB6zsiurD02W7g5OAgMg\nxGZt448GAKPwQ6dsQvd2PUCImOjNlrncUNXB4avPbmn7k9icqZXscsq3gruY\npK8VATLhG9bxQY1XYsZ+zW1IGY+PeCw5rXPFXd5CasSmZRcvvaW7JhF/RPV2\n9oklghp9rlBCq2/NM+9YUIev5g/Wr8uChllNrgDAaipguyDTp8lsfzyljvct\n8oQL/h+oVVuV28Q6nPBZ7ccGyb/gewDfMs4UFQ/50lh/4nzcWATOH+3Mk3Ry\nzv5AERQbrXb4I6YTthAnHHLnqN2hGLanfZG24SLXaaNS555Rhy0la0dhWsJi\npONNxRlkeL/GVEigaLFt/gusWDXVVIbPJOLjabfxKEXj2JnymfdILpdUAU0L\nL5lzwNSOoYhtNrYOh4wyXJmlUkh2+c3Iul7WuFlJwTebwP6Ra2zcfNShOiO8\nKWmYfcWujMXTJIgnJgE7v8oyZ0JPyqFjgtEJA2J1l5dd2tiaf/JBeBtSrlgN\nbWmPJTqJULzTYu14KRd8tJHYhnWEuhyKsnKKDxG2Ab72xeLDdsr9l2X+5xUW\nrTTT\r\n=ZevN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCq74NkdnUFMQPZoQ1WkWSjzowfCYbcl6TswuCRpnJ/qQIhAKu29jv0+aEKBSBH02S6QMRwauj2u8Ueb8bPx1+vx/QA"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601680608.0_1601680618840_0.7451254435322023"},"_hasShrinkwrap":false},"1.6.1-canary.1601726027.0":{"name":"@joist/component","version":"1.6.1-canary.1601726027.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601726027.0+d59367e"},"gitHead":"d59367e3bd29fea2b8c2b874809bd4d2c1197fe2","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601726027.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-BV+XS/COUFDMiypFCZjiAmNpair/FK0evvNllJ6YhZUfyOGaOifuwTHgmAfa3REa2mXTXVRWgrYV9JG7r67P+w==","shasum":"9acb4e034c2d51b9b94bcc83ac51f4d2941c7a79","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601726027.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfeGZUCRA9TVsSAnZWagAAhRcP/iUe8J0qQImJtGYlcHY/\nVSqM2Q7eyrsGSNwuF9ZbgFoy1dzsamoxvyqXgHuul7pwncmFHU5bKu4wBttK\nQeUdVX/OsLND3ivLmxvcvI3jPQF0r69vGUDTBLjiRilkr0nycNtAE49pwfiu\nzBCSs6FORFUi0sx0M/WUqHJN/mYQMdY/tYsH8jDl2h26eU/LRepW51yGPVHP\nneHlSWQJ6yL6Ex8Oy5I14x1jYlMTVWzGTT3YrCFdBbJWFkVRaTYTnKAR0RFU\nIfJ0KjXyEzTWD+aBs7FZn3JxlNUu+pZK/HriilK0LoOfaMhM7OMC3TsJBYCc\nvsU8l0b+LkypfIx7cd//F2WijgclEQ+Oe4hk6D4ohzXDW0ngsceYLcKc594F\nSa3I2/kA+tfr6a4Pk8LEvGHjTAt11lJYqTqk78vKMqcGjXtF/8mIWOnLjknM\nK8kmchEhDMwpDwWYf6OYPqIpmDJeGuiSqAg/YSt+Z9PdV+ziyYg+BD84QGjn\nUWx+/Ol0ri3983ll9+NVS/3nox+GX3/VnoZCiR0EgdJeGwMPcjX40NIf6WH6\nvRViOysUBdofydawAKo+NTGIvY3r4YBGDewFxJUyQ2vy9eDZb6nqSWRUQ7B7\nqjkxTklnf/PSduPMG6f4+1bgEd8NQIQw2/oET9N61XMI6u8ZUZrMDweVhO+g\nt86t\r\n=jC6V\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD+qjrn0eg5dAVTon9oec68Orl3pqG7xkfgPKUAnEOeXAIhAL7eFXrXOmowzVRb85U0B87rY4/jhr4pHdEUvb8gObh8"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601726027.0_1601726036399_0.4802086299919188"},"_hasShrinkwrap":false},"1.6.1-canary.1601756060.0":{"name":"@joist/component","version":"1.6.1-canary.1601756060.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601756060.0+2ccc5c2"},"gitHead":"2ccc5c29801df77546c397db53fd9ee9cf719a10","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601756060.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-bHH+U3dn12Uitwd2RPBQ0DAqHn3SZUpB22wtibhBHysxGgTDn7TcM7XxFGVoRTMjmtFtHKZN2OnPIUiLPg8VEA==","shasum":"1f7f9fc1c1bd77c77a5d4dd99c5b2c670b90b01c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601756060.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfeNumCRA9TVsSAnZWagAAdzgP/ivF6X1J7+e0fxymMFO9\nNFxb8PAd9nI74zrsjBpDlnNlVxFjvlVZ79Y0x/p49B3zaOh+TDAccVDzaM4y\neQl61M5bvU8Rja8nmQWRqZCbddm9WLc1rbjBVYVddluZoIHFpEh80BrKyvh9\nWmiDjmxsN936utT2SbGTIvhyp/VsbguKSTDm4gxs2zZ/2pjjoMKUW8ex6twm\nrlHPm6Q8pRwTfBIEWIduqNXHEYqfSdqDwYcLluW+hQNbH5ctTCXPKFsDp1zI\nCj2hyo5W46df4iJEgc3sx53/kYyPNZaPtux8seoU3qqeIgAnoN0vPIdJt2T7\nTcyp/MoLUBVUBJhX+pXUnl/tRbZdKxyKVKH5A1FxQNwS7ZgDgHUb3lJnXmgn\nw9DUqZpEAdnU8H0+qAfSsBakqbU7rVmAzqF7/u20m8sv4DlBs2eqC4i4Wqg3\nAjlIwdBv39O8KDo8009BLbmVNH3m793Cf0ZY8OQt5K2WYhjUH9dFB4v48t3R\no4hP0NY4HB2BmaaZH22YjL/iTQou0iiXlcaXe5TjcDPXuwPmwJePskUuNuN4\ng6Ldw8Qp47doiMlv6DCyobPhCUolXVqv+wtkm9c81Hb6XZau1y1CZH0kVW2n\nrdmS0HcJHI52GFIfEBZGPZDmjj60GP7ur6OcuQWFORQf7mvq36lNRrfKbuOQ\nR62C\r\n=tRmX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD62o4VBR4Lc4Qszeob43IH9ZO95gANTBPu6THPiE6X6QIgOca0Kcl43a3OFOrddOmhleXgf7u9N++/2d3lb2mrrVk="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601756060.0_1601756069947_0.6888029875970765"},"_hasShrinkwrap":false},"1.6.1-canary.1601908406.0":{"name":"@joist/component","version":"1.6.1-canary.1601908406.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601908406.0+12c1832"},"gitHead":"12c18327788f3779f761033dc89ec566145648a5","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601908406.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-NN/yiwz/kiYlda4dOB+Uyl3kwFj+z5v6eXKfUVzvXRWa6TWNBtu6V5x6OoRr6+zQmbd0k/hK2UPqPv9SrUIJ9Q==","shasum":"1e655d82a24d7744700ab1707138b70f9971bf2a","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601908406.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfey7ACRA9TVsSAnZWagAAq3MP/ilBZcWRuCvwoCblERB8\nft9Eu4HxFDiv21ahQReFqOoLtlBSxYDhxrh/P7KeVUCXpQYbSgxBDQEMEKL0\npLkiu0W2SwsGZUwn4wUXkvweMa8ujm2hPDODpML3MidVTkF6QJyN3J0nO/L/\nLU/LNclrrSS6XSnI6XZVcZudK84Av8Ovz32lDJiPnS33wjhOQK1qCSc11Uxl\nak0MhOjQJkocq5C7YftvOXwwnoTcwWyT//csZn18iqkOFKPlgz31Aun83Swa\nQ0IXggAUh7idOd4bV24dI4CwhHGRwH3jywcMVKJn2Kuup49CfdKyIcHOlVzK\nJfBOxqznmxaxFxAtvv07P1hY0JJGqa1VWBYyNuxKaG0ko23wAHaWq4biL+Kz\noHixzlyuvH3eLwcPwQtQK7y7Q3rL22sef2a5yFEX/Awe6gwSwCM+v1gxcgYs\nhMzrUK+PQI9qXFVf+/vmsuqI6aqgsu3Q5QGbQ2Q16t9ZWDp8Gk6bbsjuSeS+\neUNmAQcAuSOYULW6ZajfJoForJ3zlpViU9GTBbZf39VRdh2qeeqfuvVqF8zK\n+bhVGrZxV6WDzeD7BbqKuRsfVfuPd3JF7XfbySNLya1X0WjN37Cne8KDZhP/\nzUfxd4t0OL3S/Zmoz3QCMTXa36gTo8F6rDJ1nE8+r+fx2ahQyG8LRIid3vWQ\nbOZt\r\n=+zjG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBKRjh04u4aIiKVp//EvIo2Vx04Sbcb/2yUwSn9McndZAiEAqvqEIg3MrI8lgVKxf9nRtr+ZBEWNmtl6QQwoaW0azMg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601908406.0_1601908415818_0.917576597701397"},"_hasShrinkwrap":false},"1.6.1-canary.1601908665.0":{"name":"@joist/component","version":"1.6.1-canary.1601908665.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601908665.0+1c1e30e"},"gitHead":"1c1e30e0118115b37625cc0f569eed3ee83599fb","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601908665.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-Rati1G31MAq0T5pWV18KnP47cDj1eqgUdtbw2Em95T5Gmb+blnjeAoWpmuXN7AUE9ol89AzFUvVgxB1+O1+FqQ==","shasum":"27194c61006f57c064fe6813effd9ca885eb76f2","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601908665.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfey/ECRA9TVsSAnZWagAAySoP/1bw5nqUo/euNWulJ8UD\nZAaFiK8tqgpGG9uzM/VoxrBf1rtKerdcfhtTYuYdqXYHuMrvVYyvW44tqH6U\n7ybSh5Dvm5g6ezy5zGjJYs2un3322RHa5a4573DfbZNhZnN3Q+RAr3Eq9LHR\nPeh7J+yITpEVI9hPZWUBU76/GXH6aYcmWSl5kbHMIggRz7M4SHl2aTSNKx1L\n0btzxXz3Z9SIIHuaZUPTv5AJoVU/3UbQVX2nr400XxOgD+awIZXsJ3oy81UE\nnKmsPhi/1LGEAy9RWzEyWExHmOyQsUmvyzt9gQa0LgH+IDU2K4upUpSp0vq7\nclTl8ksmf/TFNA9XdjxlnHCEA72amF1KFoQaQT/yfqvgCRLM1KNz6kIW+jgx\nWYKITcwwma7rUJMOfi3C2pt+4j8PBj+SjT3UX/g0fxhOKN4l71kYtfGsHZiP\niJrhphkVF6xOQL60/DtUxcVsL6SEgw1FiMJuDLIN/pHUTZLQYK7WHa1O/u2r\nnoshSz0EwJq2MPEXCwd0/fcD9e3bYRVveLoOsDDLMeoQN2NNw1O23AFp4mb2\nQvZegR9xUryvbV7uqoH5cYoH8MjxTi2fE4RLg1oLsWt1o7mh+KpZpgXZnhTP\nnRnXwTsxEO5c47L2pkx6jppqGtPsD8ypWENPWZkQWXTotv27qk6YHM7jiq2W\n+jw3\r\n=ZZ8K\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC7A07oVTvJR3rKPKpsMIM+0/myvjp4z3Qzvw5d9X34iQIhALEOc95UL3lXhw2y7MeUriDaBHQ7wRMXC/PZTugzg+0c"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601908665.0_1601908675808_0.015931373719328956"},"_hasShrinkwrap":false},"1.6.1-canary.1601908965.0":{"name":"@joist/component","version":"1.6.1-canary.1601908965.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601908965.0+b95b4d6"},"gitHead":"b95b4d606912343e42cd5e693d18b79f25cc4caa","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601908965.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-rmyqBaKsPixst/fR2stzAxqMBJnu9G9Aiyjw8XE8rqyTo+QZ5dFpbjDWgvufQ+D78dHp/HGA6WbEHV+MJuzPig==","shasum":"2a2a8c0342fcaa304b51a9a45262db0cfec2872b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601908965.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfezDuCRA9TVsSAnZWagAAhbUP/jf4BlZYKH9m8EyfLP6P\nGDmcynS+SnGi8pB0FVvoIk+bH0BtEhP/QfaIOiDkMjp4fD27+ukSkBHDgfS1\nu/4PdzBrvDLqgu85zWnVskZsjCEyxjVdrfTHjQPRxBhr6ylEAAafAfH7BK1U\nU1lNhK2fInvs6WPwrmc9xv/MBI0doHf4yjgK3f8w+h64N1C5Q02e5w1RXwjQ\nCb8sFDcyCyw22m7aT1aGfW9G7ej4eQRDsnvcDaHTHQ3eCF2TghfFkvViOhnc\ngBR2VVeQ8c4bRi7t8B17/dEbeR4Gn+lJ5Q44CwN7RcaRgJBCQuM/1/4iC63G\nGbWyOu6AJTrGx1ZHgzQA5oGoUQGY58EB2hgqkgUaXMKW26IPI2MFBgZ4lYf7\nLxmavUWzUTR/tAOvBUcjwihVnAH+z/KUmMr0CdVWnOoNIVdsnzayqJjaaLx6\nd8wN+9zKKhv1XoZAgpjLEkVdVmwXBRK0LTB6znHOjP5KaIpMuog2wAYeQmc4\n6DZsVJmVdjLJ+9Eknevxm0kKd0mboUo3rg0/goilub7UpAzRnzZUhcck4dCq\nKvFWy5LWMVn8CgZwWGsK7qAD8utBVgqQBVIy3qbbC8bSGtN6nDUSMK5wBh5t\nxlRPhLEaip5mi1NC/NraFHICceTqjhgLI/dTIbb6+88SKucc7WZKUOYgBdbG\ngnrk\r\n=Agij\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFu0mq98LJxLXiztNmE7UCaJt1x6cP0vVbExOSPP7oaAAiEAwqsm7IF3bwVk8FsKuDc1cVv5Kr3ocKuZ5EhVqOHS3kc="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601908965.0_1601908974114_0.3082436892095901"},"_hasShrinkwrap":false},"1.6.1-canary.1601909298.0":{"name":"@joist/component","version":"1.6.1-canary.1601909298.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601909298.0+ed2e046"},"gitHead":"ed2e0464011845cf47dfc1e3283ce26554f87347","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601909298.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-Gpp5vM1lIRFtEzYUexIzM/ogMCs9+p4fhJGIYWVCNcymc8GZ/InooBC/A0asvv6E6VAfNJQZKPa8xmtdKo8UyQ==","shasum":"7dee1d636bd983c1a1171570ac54bb96e50abd39","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601909298.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfezI8CRA9TVsSAnZWagAAJnYQAIYb8soVpWFIxRfCGRit\nxuJoSp6r+ysbYwV4fxAmV71AJNhMgZdeT82oRce9iPkd7OD9783UIV/WvNft\nny790kKlek5tmR8gMha/vTrW8G9ih5NNfEZ+R6aQ8tKmzgw+pD3OPzWuG1J7\nUZv7381t/UIFlNV+a3+eW/5x/CTlHo2LvyATEtm2FRo3i2pwLAQiIJPe7TI9\nL1nNp1PJJ7ICZZtbHUGPoJlfN8Fi/wkV7xJUzjg84YJw8hZE8KssnzbQEH8U\n5U9WkKW1T1ZBMwaAyCLuALAe7AWubXMSY+aG50gwS8nIEJHqyfaloUjV8r4l\nf3i/ANP7mxGuWGg2fo3o+dwsw5bfeAERONCOq5OYLOdrCPI6rX/oR6+qTsJq\n7ZrkciHNCCIzRnJceSWXiRKk8r5lltt+TqgeLdnQmcAdO0TigEcSGkROq/vi\nfpG5AcXlZzq0RNkATQEyFrAvqYferJ/6R+4b6KOal86yLjM5SyqCegARcdhs\nEgBObXbDqSt/CBIcumUSFbeZ+v/Wkm3SQH4em0QYwGweVDxY0r6aNMGzYGiB\nqk3reKk1jXSEtvKWtAkxbmB0xpM/Tm1fyaAz3b0l42T5Nlfz4u8UQqZuESGf\nzLbjGs2c/t2FkqChLNXFjHHuK/pRrTeqJYmJK9XqItXCffc2N6imKCeBuh6A\nsCwh\r\n=YgfU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDmoa/oD0AukTd0BOFtKPBR+B0RakntH29kn5UJWtL9vQIgIqA5WYZPn65ouZgKs9equnqARf0G6Jyr0NzqIhWK84U="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601909298.0_1601909307618_0.7934498006317527"},"_hasShrinkwrap":false},"1.6.1-canary.1601919412.0":{"name":"@joist/component","version":"1.6.1-canary.1601919412.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601919412.0+5bdc808"},"gitHead":"5bdc8086fc1ea4f91ed8b75e98e6b4c82ad6c482","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601919412.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-U8wYTKMnJEXQVPDsjOGchX9FRdQugUEx+Rkdve+zK/dNogTVUM+yWy/fedenM/qy2fEx4YgxYS/tG8yWzka3FQ==","shasum":"fa9e049596360b570a85ab785fc20f23f299e55c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601919412.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfe1m+CRA9TVsSAnZWagAAC/MP/0r9A8VLN6zsZNSR3Kxv\nh4Xgl1hxLXSCNqpriD34PiJrMnXlXDnzj7IquOROhry4JhKFELuMWDFIhMe4\njehV2eD7XVibphgELNk5M6rLn0F49RkfVvDG0mwXBF9Vo1kdnSkLeCFbscvu\nZeDiZbcYFF6ULXzWBjMucq+FsFq1PgRkRYJ5DwdEL83qNG/5kNzphlS3Ig5u\n7dAuuqIEASUePY6dmK3ooOm08vNyoNiZKaxRY8h0TkEccuXh2iXpIY/8kKhc\npo64Zh2HW9So0z298MCy28fpmFVE9iWhxN4hycLfCpRi75+EFnLYN4LvaNXg\nPqMPUXMuBA/pnZS8rzAxEw17wu2OykUaYoy3hN9qAWDYtQzjaM1ZEPIMiWWY\nbKSP1rfzreBFSfT5gwpqx0FRL3DFrV2sSuV4PLpCSZl1lp+ZfIKifdP+oB41\nGU1rG1i++0Pb8p36HcMlMg4LnLHgk69I5VZHhQdR09gyhjRHqHwXnQvF171g\nPc5/mjJl35mZSvUy8BTK9WKr0Y8oxPNDmmSAmCp+vos0fY9EAotG4/RVrA+c\nItW91bUAT08B+8YzyHnZdpBWsJRmEWYq7WoVgedYNKS572A8gNhuXFTqknSR\nmzD+nGxzm6Y/+u2iwAT5422+QvjLtU1RBLRoISEcY353rI9c6RnBuJqxvRFA\ni/5Q\r\n=+yhJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDw+yaSifO0Sxglx/Rj8b+PkOt2Jchh/RBpKpryjDrVSAiBp4dIXMS81jw29fK9Ma6opekXACCjNliM0LMg4Ca1lVg=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601919412.0_1601919422105_0.1766570044178628"},"_hasShrinkwrap":false},"1.6.1-canary.1601952646.0":{"name":"@joist/component","version":"1.6.1-canary.1601952646.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601952646.0+da7ba6f"},"gitHead":"da7ba6fa65a59c2ca372d494d019d7b913148d5d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601952646.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-QzJYRiOkydYT0GQ2pmqGiSTh8Y4p6rXmfamqndTnuyvuDxr10hYTIFfmqxLrjGHBzltww5to4sMrT4/yCWbJdA==","shasum":"b65085662e6292e9518bf9a22bcffd7d4d10e005","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601952646.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfe9uRCRA9TVsSAnZWagAAI7IP/iT4SR8RIXy7+m7KFniq\nyj9fzGnZyc9FgWYqL4kQ2g+5RKB4+2hf50d6sF+j26WDeleRCa3YCJBbsCNW\ndWCV2TzsoVtyPZ1mpWZVmwrgSj9GLjiVQUuRh60J+9pNKhfcn0II7ys8zGGN\nnAnpV37AVWM7mlUpYYJfC7HGeBGLSjqxpGYcfxefmPPO1cC1rJXsEpikbuLp\nUorvc1+oKuFMd771RpcNxokc/2WbNfTZycXoAzNdBOieHxZrdz5E04b1taz4\nUiNK4RwnRdXM/FuFqTpuEyG/yJaI3qJPF9vKlPHK69FJf6lgxjXsCgnc97Dk\nxNXz/0pm1lYU7NUrfA0F/XQ3+5mdG1XKmeoOF9SPLRhDvI1xYZhrbHCyae8o\nX+mh99plImfS4sYI5FRU0YV1MWz6SzTPZOOPnX9m+Vsq1vU5w10FtkK826aZ\nPtWzi5JIvD8/52UEL+Y0eHDsCaG56YJUMBN5tAcV4RyQ+Wvv2n+B5U3FOv7/\nEHIUft+2DJglkYoDIAmuom0Hqmr47YU5VbjavWSltBzP/NEdk8xeIZT2SOGq\nyT44mo0VvwtoX8tu0q5WYHiP19lF95nN6FELDfBO1UwSW8QZbayGlVW7ga2R\ne647P5J03t+YzyNmW3Byc0VwWjS+SbF3JczEx7GgKC/gzXzRpWAA+ZU6BWh0\n4mIx\r\n=s9PJ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCVmnshsM5T1iG5pk6yqqxk3hA8EUXtWLyJmfWU+OqLMAIhAM8YmbFelKYV6mGF4y2zQeg8Zvijb7bodsDUF9m6TS3n"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601952646.0_1601952657108_0.9119216670445354"},"_hasShrinkwrap":false},"1.6.1-canary.1601991516.0":{"name":"@joist/component","version":"1.6.1-canary.1601991516.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1601991516.0+eaee8f5"},"gitHead":"eaee8f5bde108d55ef33cc5b570829dd47f13a98","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1601991516.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-pv3rz5uwO84YHm225Oq9SCDMdLrtTFTn/rwY2o9Yl3UVzzFh+6b9uJsL3Rol6vt+/nAhqOtHdWOphPYO+NszdQ==","shasum":"3d875fdf4ec2ad7d64cd68f82fe2e80022f47e67","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1601991516.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffHNmCRA9TVsSAnZWagAA1HwP/2zRKFr3+zjDUiaUQ9oN\njzNRdWWbEOWcFUI9FVE7MldRL01r1MAWrQsgxt/DaEUyDExFRFDeoGuUVLu+\n8mgk40tSc4mx+UQlG9Pbz28xhNBJ9HyfCN+ZLdw2rLYRdURqasXxKJ2zdgVR\nEPwteUSvCXIimRczDG02ejw9N6DXc3/dgusaawOY8mXE58v8/BzeAcPpqTyd\n+PxO3bm/Cy9FHSC4jthmXRk3lzu3wRno0zcxGdKJ/aoGmDHZASNaUOrP6YH7\nZ47OBmNaWO1K/nJxTHfdRguY9E7u65QzPVC1y9vHH4i9n+TV4AdEqtkQkKnF\nqZdffJXQwIkHojVBZktIc8pqDebViaH8T5huxk+1rehyhJNTombQv0VueU5X\nAMKt/0Pr47Z3ed+P+4QGesq5pS3Uay/laz0epMkZUZu/V8Gt8cpE/MtiSOsK\nuxxW58yzoClwpaVkr7s4eOYbRBTGwIMZWLXIizhngJmkMaerctyX91MFbkZh\nHPDKTTQVoUrngJiho4RVXgf7P5d1dd6emoGBr6JmGLwC9A3Nvr61gDSZgRpY\nx6FtUSf9tMww7P6uJF933en+ivw445g0p+TFgTj2V5rraLtQ0CQZ86Gr0dwG\nZCpPnjDhYSU7l9Cp8MhNW8Yxw/oCVK8FtRHUbsAJtBUGuReqiCIfljbKYktB\nCKrk\r\n=Yl8B\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAMjgD1oQHlMXn8m4lqrhedDgC6SMJSl91MvH0KGvvTWAiEAvHi1qhsfufxAjUTsk7/YOqoynFr6w3s0xMUeAT/gsSw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1601991516.0_1601991525926_0.8858612010600941"},"_hasShrinkwrap":false},"1.6.1-canary.1602000049.0":{"name":"@joist/component","version":"1.6.1-canary.1602000049.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602000049.0+43620f3"},"gitHead":"43620f352dbacf71e3592954e0ea53b9ed0a8eac","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602000049.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-SfXfgZ7jYQoH7lQ5bplEDDg3hTkWk0sxF7oy+ElcEiL1WakGJm3JZy5NyHWd/74QG9Qf+UsvOe79MImHEqF3Bw==","shasum":"46ed50769a447a1c2578783ac8033fb5e50ff473","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602000049.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffJS8CRA9TVsSAnZWagAA9cYQAJ1gmgUsLt124IA7NugI\no5wd+qWO7y3MnO2PiBR0vlfvEpug90b7rON7ADcgBTspyQWsuuYgDn+pSMvc\ns+YLwVUg415kk9Te2JsT/aKSV5MLG/Kjhal3IcfB7huMXecMBj/AxfbwUXbm\n5AhA5mkbtDKPZUflBzYHP4OfzRwDrUhOnLTc63vtmcRBRGnYt5aNv7svd61h\nhGuJ07glvMXJXhuOIDsaUA7UegXB3MauyBukUzooiP9mu6nW+nIdcqoYJCAp\nVIxUpXJ7N1itr19JBlcU6ouaqTuDzZPn8oEZ7G9JRwrOambdoK8r2wI/81lU\nH/Cnxf9jLiPLfuMp1lA9WN2ahCcNaeNDuRS1SgK0pskCMFcdrhIGeT8b72J6\nvWw3lFrHrJsURMc7RaSL/2HTUNBJy4ALWxJtYiOPcKtlQyw81zKT3bNLEYvg\n5cSj54I7e2p1Hr0JCovRw/o/8gIW8Wp5aeVfoOFgo+vTAy9u4o33C6NDZwZq\nZf2qio3dGuSyCkizIeZR2ZJqeyOgVhL5pR7+enzBZDyM3xtYiVhwmatM9AJP\nMYtGOvUwL6AwOaXLURUFinxLJOVquypm0SF/v3Nx/IPSTZnA2vK590m0MVIQ\nxLu2Q6iDLvJX5skd+WRmvT4N+/Ql6n8rQ6Ha0dGIq0J/Kfyx2Ztg/kKMMODK\nJH1m\r\n=nKTD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIESCntZ0y6oIZBJjScEAwtBMZAl7UzHeKkF+BIiqQdqZAiEApz+q361fZ/5PQoEArbHW4Nyj8leTlHhvwhrV4IYxhoA="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602000049.0_1602000059662_0.270033017177592"},"_hasShrinkwrap":false},"1.6.1-canary.1602012693.0":{"name":"@joist/component","version":"1.6.1-canary.1602012693.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602012693.0+9159c95"},"gitHead":"9159c9575f6b1ce0a3504dbafc96a01964a6c2f3","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602012693.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-Owcc3ImIApcj2GSJtr72oyiNYfWXntfDn13a/gFScbUhJ8PNIbFWLSNCdY1YOr33wIoFrgIYX/zLsNuG9rEniQ==","shasum":"56139f493e8959fea794e9973d9d973667a37e2c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602012693.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffMYlCRA9TVsSAnZWagAAoEsP/i1sz5GqTb5LzWXVG7vM\nLKVgOYTwOEq6Ofm77eiPT5dAAcj4d9T3rG+v4lFCUyXsxjhAu1U8XQWhdVd2\nULc78A0Izh48ht4JaCukNmbKfwtpk+VXadOTGusvP9FjQ9eML01p3W0qnzkm\n71zRibqdg/VdVxy3zgeWlJkPEPw8/+etzpS5gypdPSF1LGmMVNE1zKlDEBqM\n6OqrDtFgyNKcLzc9uz5eQlgUBV+VvmuC/EAQkOcdrvWwj82aoQWEc6v7T5Bd\nLHw0UKZ7pohI0DuUIU7SMHUPN83Gh/pFMUcuerfMhweg0u/BGdoKnoO7ufNW\n/z3XMGdsCyOOEoBI9boGkP5YljlLucfhePHnaan6whUmZTm3ti3CQVpBohRI\nKgE2mCiutsgbt/yq89OiqkaYSBIqT73jeEjp5udl0Nk59oR7K2CM4asZcu3F\n8T3YnKfNCM1/mMZK/OKpW/FOJ5tb2Ep6f92pWQaZ/qrJLX9Sem/e4t/oVeFI\nF45WKyixg5OHpOtYjFA7eobnNoEOdn3+8LIagH995nLtQBi6TqrShvmYyB9X\nLUdtm5Ur2c63aN3LvLh8SxqczXirpwbos8rZYJS4JniPFhof2PEZLyOBASn+\n9hdNd3pDv5dk7GYyKlZZZDvFMWaKJ9Ku84zyG/1Hhat2FyzCH1yiuS+/qqfP\nF8VJ\r\n=Z1wI\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDihm46uA3wpgY+HqSYqjJ9PLyops3gC/zHUC3WWHRekQIhAOTeFTCpNlHRWNehgADwLGeb+x+qFCFEGHQ4fn5x8Ux8"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602012693.0_1602012708351_0.14715030290645625"},"_hasShrinkwrap":false},"1.6.1-canary.1602108254.0":{"name":"@joist/component","version":"1.6.1-canary.1602108254.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602108254.0+be6b9a0"},"gitHead":"be6b9a04f304fcde8cc38aa5c0ecb970ba03420e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602108254.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-eQzpf1nof/N5MFxf4JCKckbP11bqztXQmszzJ5OJhrAqKFeGLjYD3aQUZ90qyx0zeZ/0SgbnY8kpZ5MLg41sJg==","shasum":"e7353fb62b77febeba41c4a3421903f0edfb1875","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602108254.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffjtoCRA9TVsSAnZWagAAjWUP/iKfMKoKBydiBQgp5zmO\nuiaxVOKxwvPa7dVxr7ql8oQZXmKYJF/YzwrbVjfHWN8VKAwq394PzkkPsUeB\n/xGRVwKs9D9jxyLzk8amx21Lr0bNLDN7Coqux/OmJ8CL3zBNw1Hy0TvgjvNU\n53Bl+rhg++FQ+jxlOzrENrHXvARMrezqRd0XYmt5NOXM2Ta9xodvQpm8FuZg\nr+71fr3Tx1LQNiYy6zrUaZtm5PMHEQUWBmXIMNEUwMBev7GzUlNrVarF/gxC\nwzzBWUqkX6yjwgarQuLMxjGJiHYESqe55AgLVURYAv4LuPephXaD6lyXE9es\nf7cnC1hNOFHAGCLfVOP0BDF7CG7CWUos9NTp11lW5PoOXf28LLF9sEl9qumy\nhLLMjNOXHGnKXAH1lVXt0v/FCGDm7Q8YCQ81Vfqp0uyNvBt9eS+X+KHUvp4N\nR79kFd3Cuz0fSN6qtwkgYaLUlrWoL9x9bJPBJcUQONG+MIphzZttx/wS8MWh\nOrK2CteYlVcvYy1e0oPRU+3i+6+1wEr1yvV9uVatnocYJgJn35zx0AiuZq1C\nwMEMtAns3fYGQxUgk22OFamVFWz9jip7yy6C4wWD3e3FcAkQ1VcqgPEj8aEs\nHetxDj99b/wCbHyira6uU0ef1yElJDAyjyGSukdxnjKqVCr3xnMQj9J3FKX8\nYL6k\r\n=DrQd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBq8ZcVxTDRw/L6Qg8wAmKJ1mDseLaecsKxtHk8vOiJHAiEAi4kCoMmzTUCjteWiwJhWIEFBJ9gyL/g514pK4J4Dgic="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602108254.0_1602108264153_0.28441565420717807"},"_hasShrinkwrap":false},"1.6.1-canary.1602158955.0":{"name":"@joist/component","version":"1.6.1-canary.1602158955.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602158955.0+61e0a2e"},"gitHead":"61e0a2e650dedceb72c969cf308449532d1959ed","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602158955.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-jw9MU1p7GpYG4fsVmv6nyxrj4HfqauIPO2PaRmc2UeaGSvlXFlIiOKaRI3uRe7WCsRskC8R2u51TNMXP2GnMFg==","shasum":"073be8cfb00d4e3ba300aab7c73ebb826264e474","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602158955.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffwF1CRA9TVsSAnZWagAAgd4QAIttG/NR4RmoAD5tPA+x\nqA2oKV8y59r2BdbMkp0370IW5NoQS6Kwb4iDl+psPdhxmuvtJVp0bkILHj4V\nUzBn55NvsN/kgc4s6coHggt+IoCZArCp54uStFFUrfQGAXT4f2O4tSya/3+B\nDMeE3RuulYN7635ku/oIr00/ZJy5S4U5COJpzMtifivwG7R7ydXWPouFBhur\noT/rKlBdBxJbdtGsooD170fBlwSRpqHz0xR5xVAejr3pgzyX/Q8vDdbIN6mK\npyVBPnZ1x0brCcSQk6AUrFQQ1mewx5tMm4Yuztjofl8qyiHvESago4ixMC5H\nhCFaxrwt8jA2vqdoG2vcbdFdhrmjgqf4tP3frTKekr8qA3yALk/qu4c7T+BI\n+U2SbpTCfo6NYV49sbVVMcULz1BY0uYqlUnC0w7T/hGsZhKqdmLSWKCEq/Wl\n1ol3qSBMkabuimOOo29U/in/bCQucC2n0SUnYT0NbN2m86sElpyBZ06KYR6m\nEG/HCyQG4vJmxuknwC040nCYm1bgHtHhMBuL1uUl2v4sMdGR3ElGhahsrViV\ng8slae6CrpOkFdSy/WtZjW/VhvQjcqnTsVAn3JK2TBkUWldMjU+R1pKuig+G\n1/tC5G8luMdToINoudGkslj1hpD3YVUWY22RZo3x9tUXREmKcs26j3o4MTSf\n51DG\r\n=LY9y\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFNPTNCNLjosV4p/0KWdMJF/CyM8gorCo02d1Eqh5wBhAiEAzxW0OtupOPtZ5EIZwobEOD6F7jKSkpGFReLvqdtMCUA="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602158955.0_1602158964628_0.44424514880923605"},"_hasShrinkwrap":false},"1.6.1-canary.1602159004.0":{"name":"@joist/component","version":"1.6.1-canary.1602159004.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602159004.0+b4d6416"},"gitHead":"b4d64160348c5975b15c588f947b343696c14efe","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602159004.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-6yiBS7l7yHDk1qD1mbmsGCD2revuUhfFPCohJRi6Rehl8QU+LxTn1GK3N7QmVshzIx38loB2mOnj4biMBW64ng==","shasum":"d6d8856ce0b84df5ca79b9ba3ba0933f48f3a339","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602159004.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJffwGmCRA9TVsSAnZWagAAQjsP/2DF9BwvkoqtJ8xx9uiq\n2br4p5pd6TwoME1Pz0JO9BmCCLn58ljnd0A81V1HvLy7gcaWbWrfZx661FK1\nUw9K3UH98axd4xNIFLe5WpRW5AaV/xBx/v455HeCPtS+1oSePbXsf/u4Yvge\nzsPBhqBm7sxoqxu05X07bVjH5vP0vLlVpUB/sKUdRlx947aC8aQdI17gkFjH\n0BmVj3kzVSUW2A57n+Z0OJQYIDTx+uM/h8Y1ERNDfe6E7vwLP65chHAQhKs1\nRCgwkA8L2aLV+lXPmsUSBRlaVwLKukv5tE1Jc5k4H2YwDy8kvzVlpk9qjl2R\nSacTYUt6KUZ6YuODkdRnHNvPvzv8xgmgivw3moE5wWrOUhFfG3NWEeZNB3xY\nVuHfc2Lf4Pa3qUOUG/aj6tc3eyashbG9U2VXi3Nu7mhh3U46KTw9L5/T44eD\nHZtfdj6OVXtI/Y7fbANLeBeHBEOritrFrj6vlk0k+IOTogPReB4JfWnK9sD6\n0PVOlY+668MyTroxW2R90oopH7VQiHE5QmycnVl+wsINuyIOl0mfxUP1g6lk\nXKtZwdeDwZMKDxpQIrXJPrUSmHXjThGV8PdDdEAzTmAe20QlfKssxFV12J5M\nYTRwmWrsQLyNfzT5ykmlDI9ODaQu7uovoej8ho8/z4iTw6FMrbDdG5/tSxNm\nqN+M\r\n=Ju7E\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDn3rcyMcKvvkW1LIrm6HoSX+ocj0qNToVVsCj7SJmVagIhAPww2qLjKpq3zXMrezzpM7kBvR/3Z4C78pMHWXMPe6I5"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602159004.0_1602159014472_0.37303921115290883"},"_hasShrinkwrap":false},"1.6.1-canary.1602249164.0":{"name":"@joist/component","version":"1.6.1-canary.1602249164.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602249164.0+81af052"},"gitHead":"81af052fbd6987ca73d1007d9e73a6260396f26e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602249164.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-4quuVqVjAVnR8M7nvXskiQKaTa6Lhdx+mhuCMMzGOWfUyIul2OU2+UfBHA8uRjKtNzugaQppBBlHM32HuFHZVA==","shasum":"482c26a4dff4eeb9a82486a68ded5387f51c7154","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602249164.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfgGHWCRA9TVsSAnZWagAALGQQAKRONrVUK7rh4yXksbf8\nPTzUVYDaeZ+ur1DAFiChOkOAso7t4xvUwAXxWaZkg4fPitXI04aB0YAhZD2O\nuXcw5+nvsJ9VXAkeZodDap5O6Uoq1dVcROrkuihg9nNsOmi5rwye5ttKJa92\nAMw/nBO5AVAKw4fOFCv9l5t+vKaeDr3UN2mngCCPfAMczWjKLw9MJkIriDVZ\nBaJliUTQkMpL4nduj8hJI5pvcDjgoa8wXnNHAnls6NUVP7JKec/65UnhsNxq\n//XJ9ir6iWK7+v8aZUPQu7bJ/nYhu5GW0/tGYseEfc3UUnOHn/zhTo71+6OJ\npN8QxtmcAvWSjF1EJFfnh2kSXJXGlGHHQNkSz2QzaI1OjRUSSk4w70ZSbdfB\ndsODt8j3EA5v7BtkvJIrO7qSdCCdioAUZN6YmkPQjjOQNi8H4jjqt6FQjZ3L\nJB9zJ9DQD0YxoOFe00WKzqBqTMdB0KtYjRfeeZ2ShjJ3ZmbawI5inPDkuxQy\nPQrsYSE3HJMxoJZ3PYz2ztET+4i9WBLMnXv38BTG0O7aT8ZDzeE3Gq6MtY8S\n2Md4qPDJMuN0w0eL3p5mBkU+VLM1pRb64t8loCoH12K4PfL5vNdAFH4NrKpk\nyp/5gWALbl+03s6nElf7RRMegQ+6xcIMxx69lCIKW5fTwdWFLfO0vSBrgrsA\nkMog\r\n=o0wg\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDkAvlu8CmNl9qD7sSM9+bHFAkPDI0C0INz/LE08JoyhAiEAiWnioa/gvN8UiJFpXzxEkCCdRZ5JZLxj8rDOVEg8EnE="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602249164.0_1602249174244_0.4924368992444803"},"_hasShrinkwrap":false},"1.6.1-canary.1602298659.0":{"name":"@joist/component","version":"1.6.1-canary.1602298659.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602298659.0+ef718f1"},"gitHead":"ef718f1fba03db8c05add6117031ae775a2cade7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602298659.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-PTYpcxSvJ2vv55pMpxoMQuaawH3YiWPG3575ini5mHhZBkgQ7Kxe7pJoSW8a3VdrmGohlO9wmDkwCV0vQQ58iw==","shasum":"3b997eb61efdd824d4ebc2ca96661275bb0b4a09","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602298659.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfgSMsCRA9TVsSAnZWagAAwUoP/3HivXPPvLmfa/C+2HWG\nmV6h14ItXRFGX+EaEYolocT0csEGeS9KJe52f+4cP5+hdJovWEdvH1zaRigE\nEMweO2ttXo4AZ6mBJx7ImWo95cVIV6Z8n/+AHaiq0ZVU3zTbPFVHCNWCzHNc\nDMu11KPd7OVw96Sl5fIdFFJss7rC2097HWHMyzEr1VXwgcINQMQeXOBijV+9\nyMbXIdfmQStAS0Q4uMt+7GKm+x6XV7gUJ0phBPbxn4Y5DOFbkf6SJuB0QFGG\nsPOIHJM/azaLov9uO0wLXmA8uVtHdYLsqJW0/QLp1ZnvhfJheyU1hdv6s25P\numWyQfsil/hmju7klPh5PjtRmeJj5RzWiEmXcVzQutqrOpqukcJD1049PycQ\nPaQTnLB/DpyLliUIFjc33MhyuHjSeY+DpzZNEQP0PCh0ymdXqEbxvMCpJ/nd\nzAVOjeS78vtGKReZAXpYGnjYLlH7pesUlDUWkc6lfs2H0mPlT10rDVe851tO\nHGTRb427c3qL5Z2R0c1LAn5fNMarIIrvQehkx6EFp77n5ZTlBRVW2tTWwFse\nhVTgcWdVNf/WOAqeHWAmmpR0YVou1mEOw0jkW3v3puCZJNFNvl80XX9dSYpX\n+vTHPdnxXgbGAUBv0/cJTV5S0Oeryf6MmSMn5R561Dznp1FSj3hn0/OLJlgR\n7EGQ\r\n=+tR2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCwOzooe+EvxxekW+X4C5M4p9gK4SrOSNesOGie+bvo/QIhAK1SVbvl/kCqxKnP03JoZ4uJUaEWOq061lNeJqa4Mi4H"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602298659.0_1602298667954_0.15914785952452237"},"_hasShrinkwrap":false},"1.6.1-canary.1602469909.0":{"name":"@joist/component","version":"1.6.1-canary.1602469909.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602469909.0+471547a"},"gitHead":"471547a55d49a593408f78bbb27de7db8b65d46b","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602469909.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-acF0NgeFGNisRGz6v1NrnWBYdFKcuMLyrVIykaIZhjrMZ6p1+HN8jm0Bo5VCqoaHu2He3cR9JyvTYPPkQvJ/4A==","shasum":"29882778e71434e2ddf87030ee254777a63926d3","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602469909.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfg8AfCRA9TVsSAnZWagAAbq4QAJsxLvUB1BOpcT1D6I9O\nRd6J8MYwNrM+7bQgOqsMo2EWoL3PnQR/eTKajaJRzxkL4QeGmJLVfs4rcc1X\nJPc3Bi8sQqTO8HZ2iWG5nTHUz8zXa/EZ3Lq09mVcOtzRRYHjU6RJMouv88vI\nECb6eklgX17WGYIjNYgPxYswCBwTzpajwDfHNvSbfpso+fDg4S9iDq0//ZS3\n2ZKyVRfmtLAbsnHzm8Oi8Ju6VaHrbNLEwL/JFD0hE1mOSTiJLdu+/kHyao/6\nf87aSOU5V1jb+OadvjLtBz9VaMtfIL4vHw6ikqUPdNLqwnIaV6kMeCA3anUm\nXSUzrehMAX0PznCxpJdBFkhzRyGqAfcqEys/W8m5CjaJcxzsKr/2w2akerKJ\nqexhi49wxwZFdkg2HT5M+N5fZyq+vl+XnKwLW2/nFItSsO52VuUV5MA9hzxD\nV64zyZRuIfkzAMRTFyl8k+GD8nmgzQZ47hSeDohhQgf7TxA4ueqVi/aDl+kU\nDspdlKWFqbWqfMk7IMRLhkXo5WlEnxSoy71PsFy5VPI5jMGVcJRZiBbhSdTl\nDA70YNCMTSRQRK22eN+aUMpya9LYW7qf9yvAvWyqaBr5rGLbm/+Kp2jiPHHb\nwHFOdSF7c3PgauiBmZ95z9+TWSurd4+QcjPgmtLIsVTfEFTTeUE4EX46ivAB\nIMKt\r\n=MOq1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFq6qXIQTznCBulcw2E1W2W2nbsywVFgq1J5B+uyJAoHAiEA39rsvBWUkJzBxGbmRAzmBWcuG/p1gPmZGmQXtf13nBI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602469909.0_1602469919191_0.8801626918565695"},"_hasShrinkwrap":false},"1.6.1-canary.1602508143.0":{"name":"@joist/component","version":"1.6.1-canary.1602508143.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602508143.0+f079b00"},"gitHead":"f079b002f8d9051c6a3cc681caefae3c4832d456","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602508143.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-HSjEIl7nUftXQvmzv6q+DPDFHAVbYENZVv8QXa+XUFhcZB7g0uBoiIUyYDd5Y9eWRsusDUp8A92L5MQ1cRrylA==","shasum":"f80275cc65c5d3367cc09c81db4cac8b7adac1d6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602508143.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhFV5CRA9TVsSAnZWagAA2ykP/2FO849ueFAlPiNepBbe\nwNXc0r2BZT3Pz9Gyzw/34+4QaI50JWZ9DccgmQFvETK8MkwnU9OR9HnWQwGm\nrvRAHbERCkKnO+O1LIueu+aF45JOM2ieJoSfZqm2TY1eRz6PZ/iG3AxU9aCC\nOxTgIvhiFG1LsEJrAzYPIXXIiXamQdZ7Bm29YYH4DcGseFx4wp/FrSqaW6B2\n3MXWlDV33SbQ8X9RunHmX6Ijg3audxqIOtzThJqZBq+thWYzyyId09nP3eSs\nuHiYR/OF4mwhvqKwnabxpRVIEy//FQKsWcZM8TRISTuSlTsLxaQcrZk6lDdp\n8zJNEyenkCAORBWVP1xWq0YrLMcDNMVJwIQkYlOUFtEdW2HC8oz6v3ahs4xa\n0bDJeftDyKGEwZLk5pHFhT9i04/4fe0NmOs4DxKpuE0OIwrRvu96j05HFPBu\nL9A15Ye8tQgdJEpSTHlDqHqBbNVeUkO7Emty9AY0ZoHfbSsw+FKkkcvexuWt\n5UEoQcQr2p++bbpTUAZELm1DdtOONqzmbkJwqayJXr8SLl9VLGxiT5Kakojb\nikQ2gXo2/KY1V2RhNyiPnt5MF8RF9guBI2wIUJo4r/ODYaLQ0oCmi2OCohJK\nsrDTWIVXJJSELQzwOY6JJ8UTqHlu+0KgzYLeeFb+5NPIMkLEIvwG9VypcwPD\nI8CL\r\n=zAv5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIA1NslzMleNfFKXrNQQ5aTCiWB9IhXgSnz6sSDA1OQXyAiEA7bdpC2Www5BZvaiBUPd4mfLc1isIuMINFWSpi+Q1808="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602508143.0_1602508152799_0.6563403588420442"},"_hasShrinkwrap":false},"1.6.1-canary.1602508139.0":{"name":"@joist/component","version":"1.6.1-canary.1602508139.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602508139.0+27e5e48"},"gitHead":"27e5e487161f8d36f86725f9c2168969ee2ba353","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602508139.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-HliGR21Fvusqhnb9jcUXsARBgY4vhFl0Fk+YpOYp0veoQXcnpW9BPydQyqf279DOgsSc/i9jAmiDZXUDxsD1qw==","shasum":"c90688c359fb3fa53c5508bbd88e181dd2b5a4ed","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602508139.0.tgz","fileCount":31,"unpackedSize":42588,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhFWICRA9TVsSAnZWagAAFhoP/jEYdT+dMW26sKVmjT53\nf01DKBTp7S5C9ATMdskop5mvs2HJH8L/j8T/A6eONv+CcOIYcc0DyfbmMl5W\nWrPd9vFAdQ2ebBgZ92YRjZbVnwjE4EcLejd3VRW75LZJ30VE+eLdajtDTEJU\n7rNCe4Wz7VqP5gGsw3XEGd8NjJ4+KUkDUX9SVRhS85IR+SiTlR0JFDj0Vale\nUqo8WKps80ca1lcUPmw1bR+q+PfsIpz0tO82JRwkex3Uj/7LKeMrmILrb0a/\nUMCNAa4rk7/xJeGkceJDIp2rrGgqnVqE4bllx/xpmzcApp+RHYfhy2bndS42\nrqheRk/Ij0D8p/mTHyuu/mBkD//kreENCLrr+h9W9/gzm/WXHROdTiqOzRmr\ncvv4/50XbLr498BU3zTcoX57bNLs/32I26+z02yQPmpoF8qt2PFq0A8v2ciw\neOoZt5gnhYY0UjOP8JUvmpeypzbIGf1Jti+kr/CxnkTsgsRzLAzx9eLEyBM1\ngo1AtRkWxMJ++4fdTCa59EZaLKA4U0BFerdJ55NVNKzr6SNt+12fL/d+Po85\nfKLrMztEpD9VxUff6F4csqZCF/OwWvlsKkp2M/lz8Sbl9UTxbACTP8m9JSKh\n3lme0H5VxhokshS6e6rbsO6KDiu9N/kvvbBKpPMJJHGKHDSvdd0fJ/MwXZag\nAm8r\r\n=pf5d\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAg/mlIeuTNxeocuzUllJY9AeI++U1QvohquUtPsOU+AAiBCQoJwaLTqpoL19s+ZfZf2A0quP/uD2cYv5fxE88DWmQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602508139.0_1602508168090_0.8978536185701533"},"_hasShrinkwrap":false},"1.6.1-canary.1602533512.0":{"name":"@joist/component","version":"1.6.1-canary.1602533512.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602533512.0+82570a3"},"gitHead":"82570a34ad584f3314b0baaf8ce5d14217a574cb","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602533512.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-exa/n8mPT94zBDjpsfnlB+qBxm6X/iVHUEBd5XjrtRxG4tv6jTFtlRegxBfD36UDkMYfOD4+82t1FrNhteS6zA==","shasum":"52e981640358b94053a2e4eed4387564f2db0765","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602533512.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhLiTCRA9TVsSAnZWagAAhOgP/R96WF5+/FniiMmtlusq\nRhkbR40sTHosRNs0vwEDSZjL7dEGt+XcH7P1COXtVpeJ96AY2WG3PEJa1HJI\nGq0QlqrQ42OVlXO3LzeuRQyRSCI0n9ZfhjuKWi1g1UUYM12U5N5yqpizOALK\n9dYUpOtPlvZaQNbsGvvcYo9FLl90qcf6oIzrh5GCJnSBQ8ZN4IqkSnd+KO4W\nU7jfFxxYdNomyvO6Zf78ZydR4p9KfR0dbfzkpTmFVWE2J7PST5zUmFCYclr8\nk2/kHmlG0h3YS/rifTMx2ji86OgHxq3ufGsPajm/vpxYzVjzQb4U33oMd1mn\nhVvPAoxCKgcU5pc8mIqCqCcXhWfvdXNofbEe1JqFETGQtfZel+N1Dd0p8a97\nmHh7xDVj5yXhuZfPIcOFwbTwzA1YayQ8ryRaN1YQ4gc2RInxD8BW1SNp8Cz9\nb2ZRpwCcqg89sTpHVYwv4rlfM2/5DoitnHveLM5J3EoEDObfyfWBRL/hNTtz\nGanFlPMH32xsYjqTC+le1DJlmWCrTfPdukxg7fBCDV5Qfn29egbenJOEuUjY\nc8Yy/JBI8/8lKbNU+89tOTSmkww6q5zSbljD7lxJsPPYDd6r3kc0lifVMlXN\nY75io/8iANQtDOhBxGSOYt3lfeMA+XU0c3LFpkJPQ5AI2csNpvVtyqRsY9Ij\nOl0d\r\n=GxBD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAOh28rrfeta1blTnTJ4Y+9qLvzRhu2kMhKsyI74b7g5AiBaCaWHRy3gnI0zRYple9cAlnlfrIwCOJLTRKKz093a3g=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602533512.0_1602533522681_0.2993091730343873"},"_hasShrinkwrap":false},"1.6.1-canary.1602623357.0":{"name":"@joist/component","version":"1.6.1-canary.1602623357.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602623357.0+b8c0ff3"},"gitHead":"b8c0ff31d00650ddfcdbff13469b1c6cfe7f5983","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602623357.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-kiOMxHCGv3lBG8uz4Dq1KvlGtvw02u023Ljtu67S+3/kUbvy84pn4JnHA41q+niwv7yQRV5u7G4dKSPHSPjAsw==","shasum":"2b7a65f06ee9202144761936d023e3bc81a7f118","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602623357.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhheHCRA9TVsSAnZWagAAtQEP/0kieATxLCmtsBaMbHvE\n8WIC99+bwYYLi65PbiZJ4MWXvEap1v4NhQWDZstpNTL+MM5eB8qs4kFAOCuS\nVef4C7KpbpbBZWN8xX/5itQFonpIYktIT9uypxj4am0qkcUD3zOuv2JuU2e0\nSqA4htkFzLgRCvdqwo+FDvIkzuVuH3QY7HnrjvEOJ3LPA3nDtdnypTe32lYJ\nPXTfEFRwL2se4RpfZH1N3y+3wBH6UUwcyFWJ7w6UYYFbdlV4xZwCfhEJ/XhN\nZyTuFRJFIVv54ITHe2REdsrhvS3GJYA0cYpXiKMIF+Tplq0AsN/t8HB/umyq\nVtbej2GGSvOtHOr7anxUCo//spb6s8IfoaotnjaeY7CKRjq7uRqjqCI43189\npSxc6OGv20rqqSlKt56fjZpQnND13RRjw+HT0WhFZDQDYRLfTujk2ulThcMc\nYh5ZJoBwGM4LqhMzzrQYT/8ahUl7ybaFSo1r7r04VuzjsQHYPPCg9RjTzATm\nJJJSrOQf4uFEP2XU6MnTOtQV7J8EQRhEHLzwGN5kKgre93dFo6i88ljL79u6\nVXHa0UTwFvZEPcQIZ5s66wO5NiywBoFp15pFq+/xmTYDBgP8eGNrRxfHudkF\nLu3oxxH3vxHJyn1lO++eN1taHr6HDK6yCcWMkTSyrDGctz41YlHw72Sdzj5Z\n55Hp\r\n=1QmA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCyHrxSTuwODfe/v1uYZmLp9hZti2O6DeDvCyH/4WgvQgIgTTlhFly3szrCJ0bwVrbKMrXGFZpQQupJFUbclQTjMxo="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602623357.0_1602623366626_0.5391155740290992"},"_hasShrinkwrap":false},"1.6.1-canary.1602697281.0":{"name":"@joist/component","version":"1.6.1-canary.1602697281.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602697281.0+34aae21"},"gitHead":"34aae216d95bd9710eda7671263c6b605efb22c7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602697281.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-d75jw7odwpKQAPuEKQ74F/0kzSG0DSKDLcUrvbgOAubRzOz5XBic3sVDzZkbVJZDrcvzyaYV1jvPWv3rqsFBCg==","shasum":"8dddf8965ae9f2c260dc6e41d3e4041a0b6b1a4d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602697281.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhzhLCRA9TVsSAnZWagAACqkQAJbp4nZFwA/V8XO0Z1M/\nbvxRvwq/hkH24w9OXsgJzqbVZcccUJTK9eDej/EzNRh5vI+WMCOJR1GGaS+n\nrY+ttYfSIRni6Slu1iOwgIXgEJQKcDs9jmrifm6H4oMQdaM2zHTRECL0gU/d\ngDppjpmiMPBtnO6aqSdNuF9z85hmS8656OEyVzUgJlQ3z8fvhk0L9Ahp7NX4\nq1zWJdMlvB1wnP19KWZiias7u4Ng5PXSFX45MTtcj5V10hrdSexqcpIC9w4Q\ngW9PVvfwYk19J21yzTWS7Ia+S0qJn9dkadRmirdzzSkoQCM424Y0Ip22rrrV\nDO7tqulalqZTCylTqbGKFs+IoTEQa/F2DeCGAQNMUTUSyqlo6PcgqDhWspuo\nt7Bz6ifquVuMfJVCJDX9FydowgXVSe/Ej7cwFvcsJmnol0n7rkAZoFJr7Jis\nbgs+1vZiQ0lbk5F00V4bmQq8G4BGE5ODrQFbKEBhIyrxErQeXWdDtkiZlWS7\nLy8Uh4hnSMcqFkRH2pFTmvjBvri0C39qXwaCAWjnRQGOJSRO+Osj3w7YiGUx\nrLN1nGHGPbLkQ8B+mIyS9C4HZycutGflVvJ02yxUN/rtd3h16STx4FXknqjG\nF+p4JBziUo0C7XizH2g7PqMqo4/9LaX5md04ZQ+d34Aq5V4VpmRhW9deB6Pj\n/Aue\r\n=9Alw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC3a9jrwB5vnDS7qEmWLp9XR6JGDY6LSh/WCPbPTMoDvQIgPfPbKOkVlA/NeJ6FDLxnhEqyEje5fTAl3ZxI+52pgD0="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602697281.0_1602697290694_0.0512487808509241"},"_hasShrinkwrap":false},"1.6.1-canary.1602698012.0":{"name":"@joist/component","version":"1.6.1-canary.1602698012.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602698012.0+2661efe"},"gitHead":"2661efe9a2f9726c3ca456c724a50797a6339003","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602698012.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-r5ROJSYY0/6ggPSZI2GDV3ClZXLPm0Rqvh0PwlKFO3R2ZkgW/38Y1rH/+7BodaWNrFlJ40cTu5J9et0vmOeOyw==","shasum":"08d0e001139f7beed9d2964fa6156a789dbfa6ea","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602698012.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfhzsmCRA9TVsSAnZWagAAQoMP/15wb7npc4rcRxgEk3PI\nG0Djmj7TzuWyls5BZQ9PMLxjtCywomll2ZdFGXSCNcRNN/rXelMQ/PcmzX4V\n4/673LmxMmBz2Ct9h3aZ+XWnTjGLxOpVKvXpI5mAEFRIAouzMpDcxMa4Ub/h\nglWT2mby4UFCPtj97YUxOl9jEIAJG5xbjyZDvTwwGJsg5cOWRZe/6hGFlQ+g\n8efNcQa5C0j3/h4Xat/QMGWxe9n07cuf0qCnmn8eha1Z4DVh8u8yPI3uQdYd\ny7qaGCJYhGEy8vj8NrHlquVzg23GMsBlWkFxjftA/JUHi9Pi4AxvWhwue+Tm\nwEM3xEF0QKnqrzMOoqtHYnApkDy+4YaAogdq7vU6nVpXAEH+gd1oJ0m9qQg2\nfvc5diG0eoaC0hg3fC5d/ObPu0TSAZfch0L8qG7Ea+tdp3bjM35f87QvReOu\nxSfvI9bcID8EHaAyaY+KkqgsTf6/n0Z5QgmtXLlYrqMzvTupQyhC4RlcR1/b\n5ukpNqhN6HTZXOE5CtVl/3sle9xiJ3d7Nuu5hLJc11I6M0mVZb0AhX7t880q\n2iKdr4YNIfpZX+NO36kncQYGQcmqyCPeyDvSUaBmfpkiWUg5V3GnPCjsOvwQ\n5ocGDUIAEsJS+VP2Xb17HN0EVES8+T/GbY5TWrKAvf/Vd+xqSHmdu0XmUz4p\n0zCM\r\n=N+16\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCQ9qs9ESUfhy/a3/NtA+QnFrLWHaXX+MAW3Ho1c3b8zgIgLV+QOrRl6WcH2fywZ0AwUdVeQMNr+a88pcB6OXzniSY="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602698012.0_1602698021952_0.18927291465767815"},"_hasShrinkwrap":false},"1.6.1-canary.1602716535.0":{"name":"@joist/component","version":"1.6.1-canary.1602716535.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602716535.0+761404c"},"gitHead":"761404c6ec877dcfa7706975cb1fc876e75a5fe1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602716535.0","_nodeVersion":"12.18.4","_npmVersion":"lerna/3.22.1/node@v12.18.4+x64 (linux)","dist":{"integrity":"sha512-8oJ5BhXFjOqf4uKSEPzrqw4hJkWzwa45uZDgzQmBVuWjctVDd6AhjBMh/oDkuEn+1S5iIIUabeqTXTERmATk5w==","shasum":"5df2d061df72e951a3498c24748c4fa90901e46b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602716535.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfh4OBCRA9TVsSAnZWagAA6I4QAIvZydIXujey9wNlJmIN\n/6k9bXe9+Jno8UG+KTkywigHZqWxeZV+g+DbNvkoEJ7EMWQoSqKq9ntUtPjU\nZgbo5mcBQEstv87djw2CeieKtHpFAt1r6WsWUjpk3kpwBvDHrsMI8u5yrNtn\nV3ZMDhzpa4Ad3WPMTn/vaw7K0a5qOMrwgnfUQOxyW8ZlhbBo1MvEm8QSUgMV\n3NuYJFt6LbqRNwqYeM2kK66RTknI539PoQTl/VJgrE4visJlVG/TXuMy5NcL\nI664KUekI/VhDN/RsH/d4LDukOEGXzGPrW3Fchr7X+jrlBi7qDyOUsJtPp8S\njQSAa/djZ9Efk+zcGMZ0lNkJGlHIEoR6N1KleGX86xyq+5tNCzRDXQwzUFO1\nnOQBVFzunTekZ9BcPcY2i2CibaTsCY93fWIqqGnKPLtw++Alph2+qKb50TC0\n2zAoIxMsI+KXkQ8kN2Sp9wiJCzCaiPJMCNzrV8taI7SpmrHXDTNj3BxZJHGq\n9neX2UhdhGQ5XQ+2ePI1Fc3EWaN7XKXddukmJgHRLCm/sZb5gNQdsTDRAmAj\nIRz03YlxBxGMY8miFbMgm794yOWim6zzajIwTCjgiPB3FBw6QaJG3Yx/kR3E\n3hdpE1tAAejvgPq/D0GIx+qfT8prk+W7SXdruqWHPTguRru2QrWQ1Kq03YCi\nnTc9\r\n=BlH1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBmG0Xi13etpZ8Ugn+M1tHIzQFV7pvI0+/P5D7FFzrH0AiA5y5wbnPC5J89fmzf5ec+Xzc2pV+frjkKaFHVrYW1Paw=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602716535.0_1602716545260_0.2753471321494385"},"_hasShrinkwrap":false},"1.6.1-canary.1602790518.0":{"name":"@joist/component","version":"1.6.1-canary.1602790518.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602790518.0+c6bca32"},"gitHead":"c6bca32578f8bebd55ee561b2df6020b068349fc","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602790518.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-KZjTsyO3bF8rpa7aEeQoUvVauA1eLQyw0R/S/AI+eUNHjCcOUbzKVXQCAp9nmYhNOUT3uznTekqAuocydIxocg==","shasum":"d642d2d3f4db236b284b3ce666a2357c9c830353","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602790518.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiKSACRA9TVsSAnZWagAArgEQAJc5wJBPIScVs6ZMh5fV\nfjxXI6RfglgEutw7jtNh+C27ARhQJzkFY76+Wo4yy//XJ+4rwA19Yh3sKB5e\n+lYToMNkVISvuNWu+DYENJduU+j9KzdhzI/11kHYPIogS0WdrCp8+i9AyjtS\nPy5r+fU41mjD12YnPcOH5YZfVFlUNrnzxuDwY6fahf1C3a4q/K6wwhnwfYYe\nGirJ3qx2hfrKKx3JODI8ZEelaXih/SdH18f9NeLw0yPHHrPCPhBz7oaHCix/\nq0615Z5PFknzIVTgtZfcrctqO7+uK/vCSoIeNOouKwmNvlxST/JqTxpSHK0D\noilistw0v923QanT4+hufXt+cxFuqOnwZjtZe307HqxerqrG+WLJSah++dKe\nKiwx6nrO3o7VwPq2JsEGK0q/8VAh9TVKXz9uefxmK71I7GB6oXomNOxzqHe4\nlW6VNsjx02SgE2JEkhNOdSp8xtPKgxXB3o5W9a3y72rxzNWVE8eDmid8ef/Y\ni5V3bAhG+Bv2ous4ykgonwL0wz0neotTFqR4kB2q7tOTOpNGMp3Pj6UFCaJ3\npPLo3E9+sotD8AvL+6h9h9pdiaQJpmSl4VHZ/ulN26gwkYfLd6rBUDIc63EK\nNFseLkFnnY+wDQz9WSL6O0H7pxKc0nJs+c6pNMhseVVuNSGZ/zYH3XElEze5\nZmd2\r\n=rD1D\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIA3mv8i/sXU5O2uhpJqjWykchBNbZHbBNEhxReOlX2ZaAiA03jg5QNHdrnc2SNxzyG+Tx9WSW5JeNmFHCghcCMyJAQ=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602790518.0_1602790528001_0.5574826790236587"},"_hasShrinkwrap":false},"1.6.1-canary.1602796781.0":{"name":"@joist/component","version":"1.6.1-canary.1602796781.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602796781.0+01146b3"},"gitHead":"01146b369b97cb40e6b453618f607bc3d842a60f","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602796781.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-f3E17RGzgWo2RRR7BexBHluE68ZtM0hemPcQaje5vL3MupyhHJN8UTJ6M1VP5HYYxRQzoJsdqeMLfHe7QSzmdw==","shasum":"68884a0d937ad3674824b17d28b4e739171a8f33","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602796781.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiLz6CRA9TVsSAnZWagAAxqcP/3H1N+RFqmh/dr4oR8Wd\nC1dRosuctsKiuLQwVShydb/xsrwqscXf6Dq86cT6fx0cFqTTx5SVrXeiOIYt\nLiTvoKePyaIJLeo3TkZHBzry5i8X5zaGP3n37caufClE9Dz2ZKXt4dnzKBHf\ntGPIkztafD8Ajw4APbpEK6NsoSH5nKwPFOGjsU5GjhCemoFG4kmTs5ZG9OXz\ntSpd6GsFfXRercIL3z+KbtVj0dkuR5+N30udSQ7RBJyIhcwNUoSLY6Gvg4iy\nrxOGTczsf7ty4JHWrtWIoBO3Ig2/1z3jzJ3m9wfTxi2rz0J6CrOozhw5qzCY\nk4Crl+QE8dggyvvmFymBWmZPKgul+x2GgmY6kVMosAyidO1cqUUoU92ZPz0t\nNgkGOiybmyhkx/2Pgf9pb9vJq5SpL7GtPEreXMozG7OckYngj9NiEvd33COP\nblHzj4ZWzWz4L7CzT44jqxI1qHq02E1BAduaOVKdWINq401RyLp9feTxuAxE\n1DR414gWVvyAyqyfY03Sn+CdcrXXj3iH7DZpDeCo6FNrQJasOU2Q2WsS7gnp\nQeTXx6MZ4Y9dUYOflqRYM81aGZtYctgQNrGIf0ikzbMb8InEUwggPtNcp7Qh\nON9/6QZRCaJf21Qc58JJwtT2106r02xWcJrbfsev/G0bnhN/maDAS+Rc1+Sn\nKwpu\r\n=lw7P\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCEOcYXwtiyNqRm5tE7kTgSH4iON4SfflPSO+/BXyNrVAIgZcKkI67hrJUMhNm6XslE/GpUGxxFFTwwNT8HLaYKv3c="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602796781.0_1602796794368_0.9283922607582134"},"_hasShrinkwrap":false},"1.6.1-canary.1602853627.0":{"name":"@joist/component","version":"1.6.1-canary.1602853627.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602853627.0+f5d7112"},"gitHead":"f5d7112e6c0204cc5fbdf2bd30e5dfa7cafbfb55","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602853627.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-wSfGn1CTKWdCXfx2tHxvE86sIx1F1XB6j1UV88rOgEPdrAf09cw6yRQomv5d6dMtGIg3mdFBjyIGC/2jo7pg4g==","shasum":"8ec74a3fba86ca1a61eee0d708a1d1a38a9c4f8f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602853627.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiZsFCRA9TVsSAnZWagAAjToP/jVMYjLQ5DcXBBtpu8mM\nQhLpJG+YojalCJSXZavpvjgsc4XmV7vzk/dELe6fGyM2CdXLE2g6ERP8emNN\nhmayZHMz1Iqa0l+xPrWlfjbjNURuMCBGckXQEUrPKEbTrS90GUxND0w0Cj4s\n8A64Cx6ZzbahPfvacqHz1+83LJlxfJB21X6D+8nKFIOGqXdAOGwJhuNT/B7/\naFwntnbpUGph+3aVAzvZnQgypYZgXXih2jsehgg5b9NjV0VQES1zMPwB9Tom\nPPUeAdfk5llU8xTLsxSOmvmExBTGp+2pPXYUoAin5xNwIwAjdlJLuT6lBdBP\n/z5n6+r0oEKymgu7DApsk1h2qMDPk7XaX7FMyou/bF1pFG4pF8pjYf5zhVAe\nRjgXxQDPqTPsGgGR41aNb/Icpt6yBYI1nF8qUqPjT2Nsczum7Tuujah+JXQi\nZj57qrPN0VllFqxPNqA27e3TxYcakvU5GCicWx8gjv2ZSk24D7lQchmMwRaG\ni2UJRmivf6Q7RC2oXohSQeo13uJ7eshxDFbDIq/BOnIlNKSbNdbhOHPaZXdT\nl1wjLwSMJmL/IGnUGaCPxHY0CAz0GKdBJHNofTqSW4ypdxffeCQ8vUGHzWyr\n8XPbN5tm1hbTy+A3Tv/weFbFws2Bp00KmQk5YAqSKxmjNVyT2Y/AU7J0rGKa\n0+Vq\r\n=V5Uj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC0N+gloBSfT7afUduSX7g1NpHKQzjKO99kjCglGsObyAiBP3sEJRxGPNhtIbKhQaYt+Oyib8yNdeoTUxP+Tp7zE4w=="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602853627.0_1602853637101_0.22063187924627203"},"_hasShrinkwrap":false},"1.6.1-canary.1602853637.0":{"name":"@joist/component","version":"1.6.1-canary.1602853637.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602853637.0+970078a"},"gitHead":"970078a1e65611bb53bd3d146fa9ac9ee297597a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602853637.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-6f1DDuTqtUwwNGAsionAaBtncbCBchoH1FeVOtcQ4mD/0ApDhWsn8BRhNcwh5+Cjh8wWLZrHMfTjlP/sPtcDtg==","shasum":"509b7e2345e7f0be2c3b8690612a5742fa07fc85","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602853637.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiZsPCRA9TVsSAnZWagAAOF8P/j2ewhxJDFXUv5wijeD3\nm7G+Vu7A9LaQilshwPeDxfWXXmSKZgwC76J2SoqMgXOh8lKXRieFry1u+cI0\nmTe1OJcDuYs3Iqrazmnate+u9CQnZ3gyXFAZKjvQ0417KPcxy8kfqTrBUkPW\n2Mx/urHxJosoFP77qvDHeRDM92GDpFXfS8RLczB6fiRTB6LqeocLTcSvh3Jd\ngphjc+KnrZWZSkrO3k/dzKCXU8BIGsbMgVsTRM769qCwVtV7RjIC5behnjdw\njGz6WRfYQatucSXNTkr6UbYeHjhhKmkpXMZs6nJaJADjXdU3dB+OhQr33MQb\nHOlLgwdC0Zuf+Nc9S/J2SFrJOkeZ3zzwWykrnMId+0D6SCtz5+qmXCwgblC0\npJ3/8CTdlH1+d4BKpkOlWX08guXiWPOi1CQ37Cb3ug+3dG5gjrARvY4BBPyD\nYqMRW0vTJtl2sdWKJ6AYy99UpLCvdRJj7fwDCLQXAzblwXJyoA90mc1c/C73\n3Y/Xpqmqizr+vkZZnXvDImilkg0nkA0Y+nd3OiFURuM3TN9zKagsyygLCGhy\nz5sC5X3SbsMt7ytiSSGFCpKMMUfkibUWro1teEfaNQsjyCyEJpZ3lgRmgJQ8\nH6Y4kZMvS26ksfSEUSd1qQqOPoi15yDngfk7RtKf/43VhNqTkgyEsBo/Qo4g\nXLVX\r\n=ZzSK\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDvt6RDVbM02EorsjS2gCr2jKiLASPyPuaTgcrJT2QViAiEAqSEg3Wi37IK9T9hm+B7mMmcppqpMWfIBfV7w1MUicGw="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602853637.0_1602853647358_0.042824889923860354"},"_hasShrinkwrap":false},"1.6.1-canary.1602854443.0":{"name":"@joist/component","version":"1.6.1-canary.1602854443.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602854443.0+8923ca2"},"gitHead":"8923ca225d184991a1451a28c2e47224bfef195c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602854443.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-lR7hchsExp+0N1pXbbfkUKPxT6O4cO+AdVbFg6Cuy54mRxNh/svnMfTUT0K2kO0uTI+qybWU0h3SGQl6l0hnpw==","shasum":"afe530e1c1c9d3d607597c753081863619bd8f8f","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602854443.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiZ40CRA9TVsSAnZWagAAkFAP/jYwfx0KZZcqoVogRnCZ\nOTiVSGesnpk0TiL848o59p0C7q8CjemuGlIxWVkg7OD0pmUFUsNx63uzmBmD\nrrvP8my5Csgkl+OWWu0eOyesSFYm/RrnGrYs6MgmOXE+pZ/9w++2G+Ysc4zZ\nAAHYUO+14Mf+rxujZHpiW0zRKz2egwrydRoYNjNcTiMSMuo6TsMZf6yFe2+v\nzZUmMDwHdInSE5kSU5c74T4sH0AeJu3vBDC8kJgxkNJhIP3RqFYqajZpc/tr\nhRe5bKsp6zTciadwjGdPsag1e/lJWQOJ70+3sjxF3SRCnAiH8XffD53el5la\nU3FvCjpAAG8EVEfE2PScqxg4x/VhaF5btOJScw+zKVJ02zvv7qBsruFqT0rb\nMp5kNVrvI3XTxmnwkTIqAlxFhQa6Uwx7adDaPQkjsXV5fkwUtGjpFmYb/Vru\nOj30Rp5yj8QQSkiWCbf8871exYfptcP8Yhgy7YgXeYh8iqqR4N5oN7ac8cOj\nNhAoU/hG8lZmf3Ah0LE4YnuwR5lEWqSzdo7ToZlLmz9idYfBn2biUcI5bcCw\n9Us+2bMoLcLSHuIexaDfbsC0LNpJcSBHy0moTzGQxSbMJglDVVCcBR2ZC78E\nNKM1VgmrCiCe6sBcvTHHPh/rFu1pPAfhsKeMfywjYWJpVNS4UzXq905Ym88O\nHllW\r\n=IhIp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDwUN+eMKneIwqKrpYedANQqP1Yf+hi2b0iKehe0dTaAAIgUfuSM+S/a4Iq8V7GwRc6MCxWO9N/wLAhBE4jH1ElCkg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602854443.0_1602854451962_0.26909801063775673"},"_hasShrinkwrap":false},"1.6.1-canary.1602863775.0":{"name":"@joist/component","version":"1.6.1-canary.1602863775.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602863775.0+34bc532"},"gitHead":"34bc53266881c48144d69444e5378a2a60f39d03","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602863775.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-4SCKDjuDVvYxDOSsqMXbFPmJRdM9fw/4aK8n23IEmvSuNd445Zf96jKwVRKcsIGwUXnjqaiaky/r/qsurlmgjw==","shasum":"b2757bfa561f30299a8825faabb2278b8c43af18","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602863775.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJficKoCRA9TVsSAnZWagAAFvcP/AxVknZ1qyhkSyI8KbJK\n02iQtY7YsgEJRp5kwF2dUpTbT6pnW8+keoQ+rjJFH967KCN2lIS0P5Qskno/\njXZ+OVM4YB2/sbcwlL7RzxV6oFbrq1fTJvhgWJ2bUUPfl/duU3aUFfamO9xp\ncXIRdMD7Mzn5aGez7/zpebZVWpfcbEIfy4XheNmFL6IOk/6K1TBl1xZLj4s6\n9N1p3se8nIbgSNgYpLWUmP66Jgy3UBehpW6cBp+MlkdwmMuu8D8+va9vQ7nl\nXKA73PhoofkvdEq42xCdQm3olIb0zMDtqsCseC4Q/fjZ6vxnS9zm/q6VHEiM\n50gfJazD3yiZDX4Tyq2D3aHWg9Us8GZ9lCWtq2uQM57yAwN3lVD6f+O65UHt\nfz0oOMvZVysiMwHX5DwqRwfiBp9Hgl/Bd01OUi06Tdn2DX+fomD+XSxCdYnr\n0v/1biuGr9g7Bq0KHcEMa5/GFTwJ0edaCvnTcZ7Wa9Qz5ctuJqpRLHP+3Zbl\nglo4VL0y6fdEZHZSN54LilfrlQWUD69lhWljHwlc9A4QQpy/Fol2IlIa3HgV\nnDrPCepdd6wa7+e2UG4I37sdSd03GXPikgyQx7EBfFdFKo3RgcAeBYztKXPy\nSXtB/z6uC/mZEjFMD2azLHPDAX47oux0/Fo1pLAyYRHJZ56pH8sE5ggUZzs+\nWIsv\r\n=zDyR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBlZrAlT/K1z4o4805SKKf99/v9lbSt9aBZqlcRh5xXDAiEAxLG6XyEuepHCC+cGImG19ZQvF+a5Of/1SWmRuPhUgDY="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602863775.0_1602863783933_0.719361627218774"},"_hasShrinkwrap":false},"1.6.1-canary.1602867626.0":{"name":"@joist/component","version":"1.6.1-canary.1602867626.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602867626.0+5367263"},"gitHead":"5367263e71183e45b58a53632fcc507d77b5ee6d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602867626.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-m9dpBNG3okug7At0RHmmSf0fxMyoUxY4UAO4Twb8aEbSZpq40Cn/kf50y6HITZl+CGevjWO6j2lYSZ1C0tGJyg==","shasum":"624c1e9a6cd247b567ba9c65dfe3561a77113ebb","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602867626.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfidGzCRA9TVsSAnZWagAAe1MP/0i03m3tBIpU4E5t54Jl\nJyrZymTlLDfPcWEtRiaqhc2NjSERZWKKiziAaK39z4J8KItA75cLKIH2Fr8N\nd27qj0lhCegq2LGqfXOnrOt3swxYFuFcrIADPJnGaE3jKADeLaVdmnwTSVj2\nZFaqI6BSuQpeOrHp/TJaKUpZ5FfpBfSAK1jPi93c4fJl6UPQoOm2wq3SKe2a\n8XUzy+KhylFksNJcWWmr+hiqgcnh7vlMvdr39adQfqpoS9k48mMqDSyExPQI\nI7fK3cVGg2c9MWhnF3ELva9yBUS+OFySuj2buZeMlaugBzQuZftXn4LkRQ+J\nnl3jAxcBzAQbWm7HkeHrJGTYI8iOHuZVBzAJvn9Zbfge3CSYoabs5+uVopis\nDNnsJ73J9MGQ8G+Gfi8OQPa4PyMG8UQeUwFyLgayDqjH5lQ5U0uFtAhZdZ/+\ns7Z0acss0w+e7sz9WODWyyeX6xn8xFfGIFYDDPxa6rpGIgg8xvUAinttBZWI\nlPRBtSDTQ8BnrwzcM2P2LyAanSgWFn/1hWCRRM9XJbSwF/qnpQlTTuEmGxRe\n+XRjTW1i8mtJFB8y6IQr+eTFYsluvsnyStMrKD4s1UAHJWhlPJuffnj1Xmah\nNBZju6AJjLOeRZfOfGiwcdlfjSV+7Ykqc743Q7dcnISU/U1RNT5znKbx0Zt/\n9uGg\r\n=4f15\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEdZsYvPGxgWkwnCDPI2vwTteS8InyzSs+f5S1rwZtcxAiEA81fvFL3mv06MliVf3g+OCE05kETXuBAZqGELziwuXjg="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602867626.0_1602867635342_0.3079104474274117"},"_hasShrinkwrap":false},"1.6.1-canary.1602872896.0":{"name":"@joist/component","version":"1.6.1-canary.1602872896.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602872896.0+5a65d5f"},"gitHead":"5a65d5fdb5d8e8ca47f64d6484d5d972d9a921d1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602872896.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-AuwX1QrNPHBOZeShRhw/hfIE2/ueo4keSKpU8lv1sdwvPgJzqtZQBq26V7AENb4SdCvFbn5JQdp7MDgj5zOY2A==","shasum":"b01cc6faed320c836af3916acb8d5cb3702f071c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602872896.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfieZKCRA9TVsSAnZWagAAPTAP/RDxo1scOkJooIt/2Sef\no2/SVFk+i/zyz1hXeQme7rDR6S/6YDvcJ6RA2n3xRc8q6566evd7iRg9Q60U\nsOA7f0la/Qx9zL+PoewSTUPHQ+E69VubuN8YT742chbkeqxbHvzrPxvPB5kW\nZ3xwwa4gEeEyKeR8io9W9Ua9fBZpwRzyMbNRnwPlZHHcdoHrscPa7OE1bJTj\nBBVOad3TXzOs4Lli38diTxIKPC1GuoyfrGayc9LuzcFmSsDTS674Sfpn20pw\nRLtg5PtlgGFFLcRK0o3Gzoa41645jI4AAfHkrQB5H/AStSSm18DiZ3lwTsuA\nkJCUUyuQFEYQweMJtK+qhGaVUh3bij+Kxq52ert+EUqjew5iWgrilsElhZE2\nMkBY6FTnlr39mn59m+MvJx3Z3324nZM4Ot22xnKx28h8F+LRKQMlKXTPG2IT\njVM4UBkMw8nNIEQ4qf7QxFXcey5NvDU+yE3LVsr7PBRGgPQkpIQxhTRepjv9\nJ6Ts0nvwss7+9fObzqGnaeRMoljtUT+Jmf2XBtVL4w0r1nG4ldMkSgRZevoL\n63GmSur98lY2rjTX+4mLQv2UlfUFnIZxNSOCwvXUpihMT/uL67lOCa61RGDi\nn3wgiE4DMcDskHbZXc0rC79xt8mxkZrDN627OLV9vlyT9tT+KDwg6UDMiQHf\nKBiZ\r\n=ubU+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHqXWpxWoLZvMxkomLCb2k7AbP7Xp/KZshtpzVSxq6DCAiEAh69s4Eu14+7JJyiQwxRGZchs3DZvR4MRsFUAGvVfQ2k="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602872896.0_1602872906452_0.026220199685948797"},"_hasShrinkwrap":false},"1.6.1-canary.1602881103.0":{"name":"@joist/component","version":"1.6.1-canary.1602881103.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602881103.0+e2e5bd8"},"gitHead":"e2e5bd865cc61fa1d28343390bcefe7badc79bb5","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602881103.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-kDIHQDGB2dFL5bqfr0Amub8rMx36Cll9yPaSck6oCeQhA3ksbVJE5KS+LwZeZoeZtAcZSPj3HkC+6pNO/FYX3w==","shasum":"e001d2c077db19c98c4d2446a267ea20f4406b22","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602881103.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfigZaCRA9TVsSAnZWagAA/kcP+wYtrDlEY1JWWw7xt7vp\n7X0UEszi8pSQPrwueEVv5E3wHJh8j3w80sIa4orIqeGTRrFY80zdyFJS3lk0\nv7qMb5t1r6qwvT6Nz2/EhUeC8QsBb2HfuGwd+r6Eixb1+FV3r/SSmCKexvoH\ndUmGeZ8ly3ugYcYWrOVLulC4DabHNzBTU2w2F6xZLwKz0k5Q3lq6RHehUKMg\nGtc3aartIqiFmgjBr5sz57sL8aMvDTLG2gLIUV0ke6ONiwNDHHM1mzNTfzoz\nR4pWlYcom2uuptTFFIJjEgTKO/iASUo+O5S+GG+MahWRIkPYnWoxQCG8YcWP\n/ZkKF7PHKMQ1qR1TNn0EMvKqbVqXU8O6xiyxdVzzn7pCJEiXSnj2AG5AMXN6\nSUqqBrxJCYzL3jsMQClyBl5VTlDMSWaf1nb3ELPZgjN3GVb2AWLA7b7Oap/G\n1K6WxmW2DaFf7Q+cDtvDQwtK+hcCacEXjbZ4YH3yV/kzvm4omnqEcEfRMLsX\nBsTmHGicCCd4Cvnv4rm9vj17JOqN5Z23aIb50LoARs4tECS8AfkWJ7tbFUQ8\n5aBNANMh19yYCo0eMsGuyYDAKHUoWqNQp273oFt+aWiHMB3tCPzBW+2fJcBc\n4XbeLnNt0b5NMmhzV68sBi/eTGcxN8qBn+zfeT10DyJA9s+tlIilEY1mie6J\n4cIw\r\n=HOjN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICVAgjgdEIgviPCZW4R+73Xr+5aPYANyyyRvi/oe4Q3+AiEAmuvFShmjj8CSfRJ6qwFBC4/t2C9pyfh/lpQkYI+HTPY="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602881103.0_1602881113942_0.41836552868775767"},"_hasShrinkwrap":false},"1.6.1-canary.1602897667.0":{"name":"@joist/component","version":"1.6.1-canary.1602897667.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602897667.0+4e32290"},"gitHead":"4e322909e7c1a41a008a77d57038f9eaf741caec","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602897667.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-+Lhy1RirkDx1suiHcXWpAVamIL2IT8Uzij1Z+mlCdmxfG4HssuPT2PyM2PvFRQ7BRiKQl9eAU9g5/dTEcZ0X/Q==","shasum":"ea6889a7fa70379b7dd73b862712c85bbc7a0f81","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602897667.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfikcNCRA9TVsSAnZWagAAbN8P/i185MSpcBIBRa2eYi6M\n8kClDnm5AydzcOa4MaVtIwVNQLIw2gUu3A0qyL4OCqr9rbi3/d9Ezc6FabfR\nawazeT/yDsPybu1YXiD9qlXJ//yI1HPefU0J30p/1a15Tj6eL0j5yVrBZw91\nsuCmOD7HrawB9MpkvZHSlIivqUoC9PKhLeh4XgRJeCynIIHFVnhMC1FB8UOS\nmpbI/dDqp8xqej7GdMZSTL0eXMobGSNinypbtm3SmqoKctW2k10JFLuYybA8\nvCp++UvJhUDLt3GfFLIBUwRH7iS79ATnjgWwWWyOC/abolgRTFB2FQL5hkK9\nlcraATKpphqlOEX8qnko9GBPZZdvY63qk6Qyfa9oYrKcJomT9cfZ/GF8x9GG\ngrYF0aIYPOjjhymhbamLlWg1Y+Hd07KdFdWtuUZbgIUakuep8DLFgx9ZJO4j\nKMKyB+fvYekVXf1YvxSUMUvHLqHlkkrshQf8qYKVlVkU6PqtcOs4WqpgLa4G\nbE+9VYF2cOOM4YCajgoPTKcA2TXhEIf0y3I1KkXw53UCpEny1wgpQSEb4X9v\n0R0qPPmLmA5V5SHQNkbvPL+sQXkXyz/2yQsjVBWEfR9aPd7orW+i3cM2G3Tj\niS62S8gFMp0vZICDEchGzsA7HyH/P66BYaNedNLg39KbEbUPz2w9IahERDv6\nITMk\r\n=uCQ/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAOvXJyEwi6Gd+r5NXXe8Ao4TgrBHKO49aYhMhbOcX8oAiEAvagGAsEdFWq3lYWRrWS4OTsrgsIT67i3Vm+88pAa3wo="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602897667.0_1602897676863_0.3022522995303534"},"_hasShrinkwrap":false},"1.6.1-canary.1602961139.0":{"name":"@joist/component","version":"1.6.1-canary.1602961139.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1602961139.0+7de3c7e"},"gitHead":"7de3c7ecb1962a240c4c36978d5b52c204ac3997","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1602961139.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-h7whO+/AjQOjEaioQKmaytp3/EjzLwMhMhrxSCGxbHiJGC1mqcIgAHzYKb4h2e+U8idEKQmXmhV57hYAGmDihw==","shasum":"6e3cfdb2516e5ecd2af8278e2c7725fa7768d03d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1602961139.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfiz77CRA9TVsSAnZWagAAsXQP/juVfr6E04bRDAAuW+/J\nj44jtuejVr88GdPOuCeQdPLpQLDatIz1AJjrLdotboieLEndTz835NS9SOlM\naXt5uu+DTqfCKJMWpf4sBZcho7hqMVHzFXKlSzP731WZ4Uc2gsExP2wn//fV\nvDU2ANTzdqtTq7UUzuy33iRQCaR10lfH4lsow8Yef/zRk9BdlhXExmRKEVQL\nHCDuM7v0rg9eJldrlgNPJacpm39+WVg2TuTBLkjwOee0w0yXSjdsf1Eykgbq\nLYsJi2k8MxjnmEu1S6hCdTNHuik1PDvQa/Q+2kelbcDR0zNE223J8ItijLy3\n4yvAaR0GmZHTmEUPTpTzj7L3RYm2Ct2VCqD96+jb+1HzO80JSkSatQi1BweF\nxtqNjG8jrZfOhfNZZfhTHLNqdyT6yO63SulnPH6bjMZZS3csA5cILDJLHN3Y\nz9YKnReYonmuq3b0JR9bEXpxvU1f5XPxUsR0Z7pOirjFSqig9WfS/jUOoJBG\nJUItjp+wzGAANhS3lVolgUxxtbHo2LEm0/XXX68imKdtCRiNKZpv4t3kvPUQ\n26B9/SeTE4GeMVUJkcnxANvqVz7MXwPznZ2iFIPmg2RvFWJgMzda0/yHVNa0\nMKxmABzCEMv3LAFUhPFSDbRT3tjIcpRaIb1gvScuRWlZnVsPsr7pjS1bjfJ7\nR8fp\r\n=r9Ye\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC73K8BvH6qL/9Bj/IDDjQdaGbBaEruEswA+MfXNpDrMAiEA3LHKYhmAaMXi5sME8EmYFWIaDrZ5VVvEB85LIGisAfI="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1602961139.0_1602961147109_0.7422034391347572"},"_hasShrinkwrap":false},"1.6.1-canary.1603122206.0":{"name":"@joist/component","version":"1.6.1-canary.1603122206.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1603122206.0+831ed23"},"gitHead":"831ed23e8730ed9037478d6e3ab5dd222974326d","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1603122206.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-86J2QOFgJ9jo1RmuO8eRXZc/CtuhxCyEYZtSEWlgWyh1p0ScdeSjkc4aMsk3RhJPkGg7q8nNpsjMBKk6DsZSwQ==","shasum":"8afb66c42a4f4de5c8e87707159198494fbfc988","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1603122206.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfjbQoCRA9TVsSAnZWagAADkcP/R4h8OBfn9XI2TreQiM6\n5jlhg0MZ+lcmgk0eVlczbh+NUNXlPQ2LmyTVf2uUdtZ4MthjFfRgBE6WtvUi\nMiCSPeFHeQyTYSbgQkznmvki7R3wJHadlUSoQ8DRyjYjAgBTRKiXXHyQvDYP\ncJ+bqbGXp16Wayq5UB3Ciu5WfOlRaENEAFccYUuATA99T5mDmgpPfoP0wAhM\nOlrTGG8wh3BSsT8RszXYksx2Wal4locTa+R1O2J0aSHD0EOfCnti8dI+cPEj\nqu1vcU3rZ6Ao3YK7GXKd+cF061QMYtzsWXLiVzFxRQZrX5+lVKGu43tNhRuJ\nk/ScIqZth5cfq77zlOwKxUhVNuby7yKZ0cFHLEDb//IvMe1ZLzFJs7TzWeNL\nBx6wRgFhHVjTYgIN/UNRJGbBx/GlCN5aL7whKVHABjjQoNg5/ZvO3uILwa9N\nzF5U21o0hoO35DBzt8fTj/Nlt/amwy1lbchVFDC66QEbMeMNG8gXaI0vQ8lV\nTzjXI3vgzR11wUlUJLX2BSfADtA51ycAkggiZyfTWOUcMnIxUInJHWe1ipjL\nRLAArzs2UJVs1LKv/4tN3VORT2q1EqGrF9fKZbJXMSZjkT8gLn2ysxwivTM4\nQ3J100gUwt6B+bbX0tBKzh0YboWPrkEKAsqdKGyMKDiAGaES9XI+qQfnvi+g\nFeKk\r\n=5SRZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCsgoFV9UoR6brGQe5eDT87XQQWgzvPYv5H6Awo6ukE3wIhAMj+9CD27E9d+4c0C07V+vw4gd40QLX0wydqlUVpP+i4"}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1603122206.0_1603122215977_0.8391372838235296"},"_hasShrinkwrap":false},"1.6.1-canary.1603200914.0":{"name":"@joist/component","version":"1.6.1-canary.1603200914.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1603200914.0+1f5306c"},"gitHead":"1f5306ca5cb778c66a2e898433fecc6504c05443","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1603200914.0","_nodeVersion":"12.19.0","_npmVersion":"lerna/3.22.1/node@v12.19.0+x64 (linux)","dist":{"integrity":"sha512-C8mkTMrFnK2sgHskSgN/lzs7qfAugA0CwWZ6jYr/BtSVrCXTjisa6TfNxPkPWF5TUkRgnSOzavWaw5dKjqg/Og==","shasum":"3bce5ae176c4d44e2e04af9fd2ad2bee5a7c63ce","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1603200914.0.tgz","fileCount":31,"unpackedSize":42592,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfjuecCRA9TVsSAnZWagAAZmYP/jKp7V9vfGi5VdnoVqcV\nF9OVt15UYGod71cu9kjxg1Fc9hJLAVmqN26CUZVbZOr9ggcnvLtpJ+RLTcic\nyoX9NjF4xGJ/v22DhOypnxSbK+GKkwQLlMe4lnZsqN+DhXBj7eVrwm1gihEV\nCMcyeYXXGngNW23V+Kq9ewRhgzilU9OCc8IHTJ1dLC9xhzgmRWV5Thg8uGVT\nVP+JeyDOYxupcq1LsrFKBPWyPPuZ2q1filEdYqdFGScbkWwZ1wuyiToqxfcv\nBHKFXoah2bhAOS19jArLm3MbSuQ23tmBi2R5CNrbRwtnTXV6sTj7U2BhBNAX\n6dnmEBvFahSeMYK/HX+YFYVwpX/G0WPWwkE49a/pPOjDRpnvd2i5q7DSQXy+\ncLnYlUj0EDSK0wm647EPA2KGOapdiUHOnhdjLE0gzW5acc5zACtGhovoSgar\n58KpALutSNBNaX0NAtLr9u8zUdl/X6JZ6RN1OU2YqKIIahtYXVSkXctoaDfq\nTez5eCFgFjseEyfobD7JIoIu24k4t6UFri5X6cuhzBBhyhLeb6WBn2tbSOJi\nPsV6akN9EXc/yykKFpeppspCurSPSJoX4MAy7vW6GA9q8sM5y6jNZGNtbeHH\nHdVnMe0+sFosadXmZ3Z7X6x32LgssrJyONTtukavoMvErdtSC1YsOg44LMTj\nZtmL\r\n=SEA9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDi5VblTojEnKbrOhMtTAb/PTEkqJXPlsXzDGCpRx3e+AiEA7U9Kqhx6Jd/4Z/fk6ybqujT59Wy9CuKydLRgilqYyv0="}]},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1603200914.0_1603200923945_0.9999869877721368"},"_hasShrinkwrap":false},"1.6.1-canary.1605118601.0":{"name":"@joist/component","version":"1.6.1-canary.1605118601.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1605118601.0+2718c02"},"gitHead":"2718c027914c6743dc33aea8a1672b883537be75","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n  \n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nThe simplest way to test your components is to just create a new instance using `document.createElement`\n\n```TS\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = document.createElement('app-root') as AppElement;\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you can manually bootstrap your environment.\n\n```TS\nimport { defineEnvironment, clearEnvironment } from '@joist/component';\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  beforeEach(() => {\n    defineEnvironment([\n      {\n        provide: MyService,\n        use: class implements Myservice {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n  });\n\n  afterEach(clearEnvironment);\n\n  it('should work', () => {\n    const el = new AppElement();\n\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1605118601.0","_nodeVersion":"14.15.0","_npmVersion":"lerna/3.22.1/node@v14.15.0+x64 (linux)","dist":{"integrity":"sha512-XdqP5IDNJ7RGAh398gDWK6UfEptexD/iEbfM8f2WXeVX+hG4WFjwQ4R4d0SJoWVNQNZiraesiLDeMk1Fv8kuVg==","shasum":"6209b503ae1ddb7a305aef1ec758907128407224","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1605118601.0.tgz","fileCount":31,"unpackedSize":42550,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfrCqZCRA9TVsSAnZWagAAN6QQAIiwLoRknlCeEpFHUfsH\nCeTkhFjaGqXu4kTXsVm55+X7qGct96k+QAXgEzfPdXEmymgw/MvpVpLxvF2y\n8kA5ShzoW0lHVN6omSBdU+gKGPeCs4a0xq9BNpSzWTGTyWPIwubNsvK310us\ncTDm0cYMV18yKosYPXJ0XRS56nFKh+HVG3M0zzXebhA78uyQ831YAfhMQxUs\nVICMhZbgLM+XyWibycDmuzZ3cbbtHdse5e3aniPeJJBLlT8HQEykhyiwt1oc\nffvRwXoQRR/xpgCHIWpRfjTRXWBRraUS47PHAyq3DgravtWHk8Gjmxg6zqKk\nrDGMcQvyu20UCu+b+FOM77dQkpjOPzLEL2GGp7/aGH/0cV9LL5Qyxrn/QSWp\nHbescgWg+Qa4p8nBBUaWd8Ocqp3K+goDyPeFIRTonm6l/VOisWMPfODpwitC\nZuB7OlNqkqLO0xJBZVhx+OxyN/vbO1q8EZKFEITUzO3SyjPSGulw9GKD+xjl\nJhEmVh/XvdSC6FTUpLegOJc+VgFZ9ClGEGzoc4UCsfRob5TaBL7IRsjHQUMt\nlfvevvuuA9AmqeGNajSqsUaWJtp66n63RCu+HmFKMKP1N1ZmBot4A5YkKUNe\niNwo0LH00m3nPmGxreI75/UEm6u/nc72VdKHdvCjPdomOomMjap5OXK4din6\nv60l\r\n=WZUj\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCgV58sYqrPU13uYbDd1rJyiyGRq2rtPEx0gOUH+V7bWwIhAPsWLfiAT3gjfWOYa9CnhN7PWwLyixj66UApPrAb0SYi"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1605118601.0_1605118611428_0.5540285488253103"},"_hasShrinkwrap":false},"1.6.1-canary.1606235949.0":{"name":"@joist/component","version":"1.6.1-canary.1606235949.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1606235949.0+e6ec055"},"gitHead":"e6ec055f430d7a692356308ef846cb884e323047","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1606235949.0","_nodeVersion":"14.15.0","_npmVersion":"lerna/3.22.1/node@v14.15.0+x64 (linux)","dist":{"integrity":"sha512-Bo9qEmBLtHdc74FIOmx/H+VkqpLwPC0G2SZhtjQQBYntJEY8TZLo3i6S4EO/3jF0oGCYpiu40ngyPu6uBPc7Zg==","shasum":"d40ffafc2c481d7c1760d11b9ddb0155f68840d9","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1606235949.0.tgz","fileCount":35,"unpackedSize":45706,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvTc2CRA9TVsSAnZWagAAIp8QAIaJDIUnXR9do65sbvlj\ndggrXIhsB6c22tBFdM5jGoQGIT4bsAut9C8DQTQPCYKCQb981XDRcEgVsj0+\nTR5sOgs/HSkx8kgME4sHII0oTnE4nxZ33xOzwrI9E6XIlZEqGKVn0irvJBgg\nqjhek6YCNP7bA6iCf3ia8r2VXVq/8Vd7koT4LR3otp3DmSlxpX4XCkcwKzLw\n6aYyz4Iy6ClNa0526vfeE2x38FKHIvtkqAYoAj6FCLRQgS5/CQumf6hh14dQ\n77yUqnBdIhUp+wT9lKUWY9btCOMgqKgYZ7raiHoXXm3JP2rS+g1r92nukca7\nYO/UjWzzM5aFbQ55s/6Vt86DEJ4BlMVcgYdGUKb9EKht+zQHWR23tmBuZZmD\n8h4VyfHU86Z+/ZcQbSJcfnDBGYHLIIclnjS42GP5Z3BfBd/sunb18Zz2GeU6\nY07DFPLAlip7FVvBrosb8qVaiWybAcGsFCvFvvRfY9gOFmhdIwmImizAZh3s\nO03VvsmGhYig2wTyHI6TpkLPnJ8SPSKa0lP6KrpmKZnLIdab4bKbED32fhMg\n33UsTchMItZ1SxK0o0xVZK28Gv4fMl3VWDkjGUcjpDwjz3sfCYHGQw2PaQRU\natOGPbY3qQ4GIG9O/yPPfIhCgQ/sBff5Odam21UCpPrVVB4R2E2xKLFrMbe7\noM+z\r\n=1Ae9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICBblcJHcv8ftPzPJb205R9r1F04h+LaBGbWoojAVfQBAiAgVgPSFoYW5wnxEnUAiE0QSMaD4Q3pR7xKvkcusv0wzw=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1606235949.0_1606235958265_0.8269236040778727"},"_hasShrinkwrap":false},"1.6.1-canary.1606242401.0":{"name":"@joist/component","version":"1.6.1-canary.1606242401.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.6.1-canary.1606242401.0+4f18d10"},"gitHead":"4f18d100f61a3c2ff56abeb934f9e2320bc1209a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.6.1-canary.1606242401.0","_nodeVersion":"14.15.0","_npmVersion":"lerna/3.22.1/node@v14.15.0+x64 (linux)","dist":{"integrity":"sha512-uUl71qvP9+b+rVkwekvhWq+vz86nih5mEy/VuQ5T8wwlCsDrHJ7eyhKuDVqYuRibA2jXvfcOV5G1PEvcOyQnWA==","shasum":"84819df7541bdf9cdfae8b446d9acc781c81fdfb","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.6.1-canary.1606242401.0.tgz","fileCount":35,"unpackedSize":46050,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvVBsCRA9TVsSAnZWagAAnfAP/iX6ZOUz0PIQwjS8cZOq\nVRja9IHDvzM16NhKOKpx6/B0vQKmgMFJqBzKMxiFHJBFvk9NEMO8jfphDucA\n6ce7J/taRQLy16BSMO/CLVknkCs26cxC/OwJNCHC6cOayMHBpnFsIS3KUDQp\nx5yZSnlXRJXRco4jciYG0deyx+Rl8LKChEBZi70jSu4FXKYBgGcB7i96z1Xo\nV60/5yh6SXfTu0yrN8yhTlxtVStyCmWyH5rDDtO3UQu6EiNeY+ZXffEjp4Od\nsI4k5TJwMQ5hOWNZE0b/NDS4CpBEmm032asKbKcQp9jL2+puhGPsL93WxKnm\nEC7rtrhbTIV10Tyu+tKpMdhMi/E2eOrl+vZjAj6S6j0NWgICCZAWUHYN5uKC\nlsqcQPdx/d5BfZ413OeSRw8/KdIPWaRLKX/BMcWtDB54K/5Xq8/Geo1rwpUk\nWP7sZ5puRISGsDR/xyEZQQarlYaFKMnjVXXUCubuuI6u8+W8RitQnc5fvs8C\nCA4eFl5Z/WSU32pyG6m9ucOMflrrKcGNM4zcKk5sAuO+CX7vhzx9xzg5bUh4\nup9ShqKeSRsaISE7mHGj6OCFAzH0D+K3Om6CRv4vSaRzWvAZjxtEk/Vp2gGo\njUgue0xtI9eHlO9FrAHwtd0GRDo3J5nmKXlwCv4KZKgGuM5c5yLcPkENQxRM\nmMF2\r\n=hczn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC0qAJxEhOK3Ef7Bjoz7giZ8Bo8ntJo/eN9AT7tVjLBVAiBEHN4Gyg6bKLiZURcavPFqoka0gaAwcxeViVaVKzzEbQ=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.6.1-canary.1606242401.0_1606242411987_0.3628681078781848"},"_hasShrinkwrap":false},"1.7.0":{"name":"@joist/component","version":"1.7.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.0"},"gitHead":"821c573aa38104529ea70e2b2fa53c34633bada9","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.0","_nodeVersion":"14.4.0","_npmVersion":"lerna/3.22.1/node@v14.4.0+x64 (darwin)","dist":{"integrity":"sha512-gjctDFJY9thVpjXl/S6HxWBIB/ymQshsXCEvCK6sejzh1y2zH6R8epoplf3a5eFCvjXWalpIJrzvkI/AvYz7KA==","shasum":"ca6a47cb6c0784e4739022e699c5c4294d56c6a8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.0.tgz","fileCount":35,"unpackedSize":45994,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvVEECRA9TVsSAnZWagAA9ygP/2mIhMw7ujGijFiTW+4Q\nT+Kp9PNOjYxaEEEccsKC8Qowzx88y8Rjdzd0Of8ePfgaWDUepaI1KnWQtXlJ\nH5pFKishWaKz0uX2aDmcQym7q24R0atjaRGgY2BhWwW+qpJJimWoLBJ5lDNJ\ngQR35HWEzW1/EDixXFVbQld5g6gGZOxuLiXRFqn2uF2Bn17pBNxkxzlqElRX\nrTbs2U79oL08pRZByvO6qXqV63Eg+T9n59Y41tbAUxwhYU5njNNIJ6hJxloi\neSSqOtDMU4J1pKPZTxo8V0ewIwr3lyZ2DWMso04HvWw7THYNldbgkMZVoMzm\nRo8qY4xPkv8Gsrq23AhIC26bHeFwKvAcLmaxXORRwRwcjF7hMoffKJLJ3dwY\nvx3t+z/jhUm00e2jb/roHvBEapRgAtkoetOYui4d/nS5bP5HgtV76PJS0k5v\nOINAXCCtMQGIsO3ptau/iDFBreoqeuaVBNQ7URIy/GQJfIF6h45ghfgLb5JD\nbrSFQollCVRdu9bi8WA3zNChr/2rP6/mukl578mr0rKWqnaPOqdzQEhzfT37\n83qo5dvNZspw9iACViss/Z3TTgm04UwczB4KEhNndozt+/g9M5pD6FtjiG+U\nNiur1KvX4tb9qfY5Jx0EZjWeFWTaHMOXTr+fzQ4AobWcJDlCP2WppDcCF+kT\nyvyt\r\n=FOdZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDMP5FqWtL+KxYf436D1YLk3yvtlHUwDl5AGKAQqCN/jQIgLyCBAxf2OoE5YlRYIQ3m7BjJBjDQJkDrsyt14plgBhA="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.0_1606242564375_0.7430760519917188"},"_hasShrinkwrap":false},"1.7.1-canary.1606242654.0":{"name":"@joist/component","version":"1.7.1-canary.1606242654.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1606242654.0+821c573"},"gitHead":"821c573aa38104529ea70e2b2fa53c34633bada9","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1606242654.0","_nodeVersion":"14.15.0","_npmVersion":"lerna/3.22.1/node@v14.15.0+x64 (linux)","dist":{"integrity":"sha512-ezRBmEn0NXl3Ng4mbT876DVwErOPH/lxV5vOB/MpvXwoXbc10A8SJ01fZXYITDj9h+3WK0b3tldoKS7IYg/JmA==","shasum":"0c4d3c347d00f5c44849696ffbf736aef34da129","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1606242654.0.tgz","fileCount":35,"unpackedSize":46050,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvVFmCRA9TVsSAnZWagAA56kP/13aEzB6vuOWWYqZJTGJ\n5K+I7MEix27eVc/cQ7J9oOlHexByVy+9cF0B8rnaZvNC0HDYmA8jLF/pLAb3\ndhuZu0KqqC/uaAs2wijSlnlgior6EoIb+HvObYelrjVQUA6aUNffooCwMiu8\n9KI8Oz/3DwxtW9XYlMVD/WJVEcsDu1l1PEPPVVNEdhRrF8zzvH84S5YVGb/T\nBH5EP7zoegBCrdOg7K72cj8NKbevx3i7uSNIDMW8OIYC1qbv+P69hNne7tZ1\ndw9KASqYC5Ggzzo4TNCA6Gq2YjIUsqEd3pKnteYWJ6uT4+Nx/sBaMGShY/6b\nO0jzl8bfPtDY5jNQKzjIjIPLZfqwdPJ0swvBpNTxcfbLo5YHADtJiebgf/JK\nO7fREqSTYVBW+YKmESrhfCbHi+0ozhTlfIIZjWFuwAfagQgbFJY64b2YNzsb\nvmi4XU9yxF2XGE+GkSugtKsFPKUhQSnTAv+UvMZI0DV7OS4Rxh78kxf6xHos\nw3Mw/J3sla4pSqHuy4PwinjQ5fJUWS+t7y+olxOHNXu3lz/hYfI0cPOCR9Ih\nESMFKvqnLHt37sxgOcuOhidnfPF6EIIBA5dxS4nBFblIdqNfEIrJwv3t8391\nX/zrF1BD46NT0bUIJuFTvQyweF3K/b0JYYXb0yrF2SuDO3Ov5T95wz1lceSH\nQf+N\r\n=NrE9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD3S2urWvgkGj1nSNfDIb7UkN9J0n1M6LDGDtDYbllJvwIgO3uMKb2J1YAufqUsXjNYF2kHNoWpjcIgo43DWtVGBR8="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1606242654.0_1606242661995_0.31757067601621203"},"_hasShrinkwrap":false},"1.7.1-canary.1606271510.0":{"name":"@joist/component","version":"1.7.1-canary.1606271510.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1606271510.0+7ddf2d8"},"gitHead":"7ddf2d8a21d3fb90927a217c94539697a7dc4e9c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1606271510.0","_nodeVersion":"14.15.0","_npmVersion":"lerna/3.22.1/node@v14.15.0+x64 (linux)","dist":{"integrity":"sha512-bxRnvgW9WwW5sR+S+qoe0i69fBW9EzQ6n8lgR8/U0REXYr0YOLJxVM1OETd1c0Y+0XlunCWlvcKNT37D4ryDrw==","shasum":"b3c23f2935d5d13882faa9cfc9d92766b47ffd9b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1606271510.0.tgz","fileCount":35,"unpackedSize":46230,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfvcIfCRA9TVsSAnZWagAAWqYQAIZwMscbuR1IUr2T38rO\nUcE+gHPRfDk+kVkodKRdhq/pEftMT5op3Ux21DZX+X9hK8S5IpdSRYeqvd4c\nGgoRuLZXGY1gHG3VWTY+n+YZzCgPqxhe4woP/32aEH2tvXLk6k+P8Oz/2/4l\n+5zENQmx4TwH+Ym7X9hkAkREsLZ1Xp2VII9CJVlD4xmajVwETj1rGbg699Dw\nnGK8kPKU6d0k0ZNJiy1/NBLOfWtXLwMnVLYMkaWdUBQSEYF53pKb5uEzR909\nn9Vz32N3jVzggax0k6sTmLtevOJbNEWsEw/Aqze52Tzgvy/s0Wb/tCGytquP\nGBgYFQn5Asy/NlaNEgu55dYyTsafBz0gWLTvbyzRQ/y7sNN1WxxGHoMwVJgv\nt73BtxvrDEzHLc3Hi16q5rEv+pxCgOZsyGCO8HXkHeTM6Kd+lp5JGUF7oC2g\nlrGa4D94vm7oj9tzzAmVe1c3mheO74m13eX8ya1TlaXDawKM348X7xQLPQwn\nhivBUBh+49kQ/STbFmQRXc+7w6mKPH1UDSVqOEP801YDq5qVqiKiMPsg3g5R\nblPDZH7PQDXQBGOREB0/8kxhR1f8ZdX9rn9mdAI6q+y3cdVzQjK9tXEZF3sf\nRBgJ7afrP+Tkm3FZCV7wAdAL30YyD8yEVCdMmQp0fo3/WbelVhrUIQ3a27je\nbsX0\r\n=EnhT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD56saVSf9k6OCSRR5PvshcJkbZNOOipX9EUU0ed6OUNQIgbXvx3vXjFPEbFYN5/bdO6hM8MjqXTtMxvdC2Pf4+UPE="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1606271510.0_1606271519330_0.39423988700881996"},"_hasShrinkwrap":false},"1.7.1-canary.1607527688.0":{"name":"@joist/component","version":"1.7.1-canary.1607527688.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1607527688.0+1239065"},"gitHead":"1239065e41d08f283ca5eac2abb90f30224d7d7c","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a Map of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChanges } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChanges) {\n    if (keys.has('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec_clicked')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc_clicked')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc_clicked') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec_clicked') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc_clicked')\n  @handle('dec_clicked')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec_clicked', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc_clicked', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc_clicked')\n  @handle('dec_clicked')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1607527688.0","_nodeVersion":"14.15.1","_npmVersion":"lerna/3.22.1/node@v14.15.1+x64 (linux)","dist":{"integrity":"sha512-DxY9W46scW4rxK8Dt/5VdowvzmXb8/yM76Cwq72EPbLV+xoEsZz2tSbb9yEUX5EbwX+C3aQV6sgEtVVani0Dbw==","shasum":"b28785c8ae561c02a4c370ed9eea8d11401aa3a1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1607527688.0.tgz","fileCount":35,"unpackedSize":44454,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0O0TCRA9TVsSAnZWagAAuvYQAIIMws47D43nmPyxgfUM\nOJTt7+PZ1xGscegC4OzdiqfUaz94BmonXjhISflCWgRYcfXQ07WGo7VrnyNz\nkodzAAZQExHip2ZRp3jt00i04Ek9fTFcVvzEBA+MrM+lwEeWghhVZOKDKuSV\nRcawKT637kubTVhxojVHyvWhZj2GlVnnT/GLTz+ySbVY7a6epjmYtVx94Qnc\nv80/dXdXE8ShVBEzSe0vowimdvWO2skqLjxedKdUwn3yxCqj2WFXbBSbCDjn\nmMVtKFDiErCFkyW7+My6JOP+5jnShPNQL4lXItjIlLGhDS4zHdM8SiTfpEr/\ne0y4H6vUmxnYqtNb2zsCWTfqiHzW+f4lIb70Odj3IG+77n9eWbBFnw7Ksp/t\n2DtYFNS0+QxMA/CRpVcidrqCBVCqxXRSm97FE3ZEwL8xSXItJ1Gm/mHQD/cQ\nT/LGdDbBbO1QpgZYp9hFu3+jLMCRmQVAT5WO7P518LDNtqWZTRVvkk5nF8iI\neVabq7wGvAr9jTJbcm9tP5YDbdfX/GL1RsyQiniB0JR1BxU7nQxMcGSa98rr\nOGm094/0iSpK+o6VMRdjHt26hkOsFjEJg6AplH4/q6i5o9ETM6g+8wuzmxTW\n6V7y5xhA40hu4myufWZiFaSeHbdJ/T2creIT0f7YhWhAfvt3jqsDADR5DqaJ\n66D8\r\n=bmlS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID50rLNy8eqaJFII9YmOpPcKWZqOzQQ0Z3Haz2B3vuHYAiEAoWGIPKqyequBiOo/ebLjjPA0q09rdTA/zdzHmRIIXdU="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1607527688.0_1607527699164_0.23945811342760415"},"_hasShrinkwrap":false},"1.7.1-canary.1611081429.0":{"name":"@joist/component","version":"1.7.1-canary.1611081429.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1611081429.0+93f398a"},"gitHead":"93f398a4dfbe7c0be3db218e617ba50c050fc4b5","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1611081429.0","_nodeVersion":"14.15.4","_npmVersion":"lerna/3.22.1/node@v14.15.4+x64 (linux)","dist":{"integrity":"sha512-vEcuaaD5XFcHH4nf+u0xcqgWX/61yUinzZS++qk+MtdngHORG5z/d2x5+NzNmBZikcBxBb6whq7G1h1coQyrcA==","shasum":"14a29f3185d96d705d913af8d083b03c5d60b169","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1611081429.0.tgz","fileCount":35,"unpackedSize":46230,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgBybgCRA9TVsSAnZWagAAP7kP/RelcXkyN+DtEU9Fazlt\nK00iopq370YGU6r56B9GAXJ3Gz8XABoZG98bBrpdwylBBaDRmUJe9lYiCMH0\nt3CFJ723rLt2CZInVJDo6+VlRWSHJZEPgsqM+M53dCQKJ5hYpSHFKkrIRg4h\nCJXYdXUx6+RoxtnL6NKosqS9kmJIXViTbFHEzvp1To4IzEsUXQtjRErVjsoe\nV6SWWbb1tNU6HZo/52r5/4dZTbXDGBaDR3HvUcinZXWyY0aZwadhoSLW8zf5\nu7SWY7pWh13B1zVuet8OJaucM+Fz4DWc2t48aeINTDEqlWKEPsx63R6zqCdH\nbGc0MunMTjO9McM83gHB3JUyOSNF3I2n08NG+gWKbQZAx51Dz0P886ai+bR2\ne874He6E7+x4XxdxY5fOYtErvi1nqcriX39jLikwAUI3mZb1Gq9I0m1LC8XR\nDRiCkzKYeRZTe4kph5RqRB5cGTUSvmD+iFF+J8uMJPZhe+kEwmRw68qJ/p9W\nN6Iw9TH1FZHI7hM3f+9lHGoUftLslvKfm3O8nVBQ6FWzSaTPR5JJHc+4AjsD\nF/a+UmcJVC2LWwIO2bt6aIWB3B0feybY0JO6hwNeZGd/k9+QwwBh0YXhqnYy\nGMBvbxF+eTwxezo6RfNkgyxF0vf/TbqUxcnptXc7BhQvPc2mWfUtd0Z0R+tA\njvRE\r\n=KFH6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAO9V8k7Zr3M4xGW6Ubu5fG2Tm8WbDwzjuByjDR2nW0aAiAxahEY2LZLtGez+RtmgIu7CvptzXcGRJbGmZ1rD1Ak8g=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1611081429.0_1611081439640_0.18499079635534543"},"_hasShrinkwrap":false},"1.7.1-canary.1615491241.0":{"name":"@joist/component","version":"1.7.1-canary.1615491241.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1615491241.0+a92e2f5"},"gitHead":"a92e2f539ce591d7d4e0bbf6110705d34df14154","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1615491241.0","_nodeVersion":"14.16.0","_npmVersion":"lerna/3.22.1/node@v14.16.0+x64 (linux)","dist":{"integrity":"sha512-uIZY577GA+545tC0KtWhzCRUMGA3XGdemEURxGuo9iTNJjhuAxXtHVa65/Z2oizrQH627rC9DI+qwcQp5++OsA==","shasum":"7bc8047ea1c51e64da694516a33a8ddf1f0cf97d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1615491241.0.tgz","fileCount":35,"unpackedSize":46230,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgSnCzCRA9TVsSAnZWagAAZLQQAItjgp3JcbJKzaoWYSPJ\nuHz+APGt6D989CO3MwzawBWbt04x/EMTB/tWvGWHazMhttREOAlYwDNsYP7h\ntNMekyVyYrmNkc/FlJZCS29utSXWIdDNdhFjwj7in8LBan410xj9CAo25kSa\nSWQ+BxuxT9m2+xA5OHp/F5aErtjbglbi61AoSa6B7FeGZAIoEbbx2yXwUL9D\n8BFdGrVhfJ/jmXjkyH8rKqNz3NAXDkM2OI3noSJ8kV3RYer5S46WDpnDaJnb\nRIuX5zjqjBEcSIM+J9utNwwTh97h90wse0JHdvtMwAYVLuE2RvRwsw1BToRQ\n5gZWCnFTisWS9Qys1ud6fGoo/ahGlAjJHF6wRwZ2tdLl2C7tdN72GQ/H+wEr\nZZmnT1mku6gbJn/EwhRavTG6e143lQrJr38JAywuzSw9PW8553qlRhXgY7+e\n4qWuhuAQQ+z9LRnBEWppA8HfuqU2L8y7gLhIlVjHX1Voj0yg+tsCyy4wGFKi\n1OKpNzqosOdsDnBE3YI0PVSYi1kTc6O89AjUM+M5EzCEy8W3Im+HhJCRNT5p\nEZxwUoPTsgz4gchFwJ9/tffpAq/8F/1WF0ZcpPZf/pYm5sy6cSaB0ZUW5oDE\nMDafdxUUk3gc+9+w3Oad5iZNCvsIszQvHR5fcGynHPB9DOxxD6v+R41kSeMv\nWhk3\r\n=e6i5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDc8GfKpra2aoAN56s+dvw980rk1ENhvirNrHNyds/bpAIgYu2xtux2haUy9tkizCRnyTyeNJkztom65cFsqg73ml4="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1615491241.0_1615491250559_0.21783068435175168"},"_hasShrinkwrap":false},"1.7.1-canary.1618631004.0":{"name":"@joist/component","version":"1.7.1-canary.1618631004.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1618631004.0+1022b9a"},"gitHead":"1022b9a68ee6f2cb98fdb1d8233519e4fe3d870b","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1618631004.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-4gIIHlFaOGaRIXMl0/E6OV+9LffC8nonkqGsgUbGg6YpH0HyiU0O9DP5Q6CU5f2KY7wO1uFiXZ8XYv/lrEFBgA==","shasum":"f982edeb095b27011f844757188ae5b4303a40aa","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1618631004.0.tgz","fileCount":35,"unpackedSize":46230,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgelllCRA9TVsSAnZWagAALHAQAJe3sPrTDWjSml6t2kY8\nbfMTUuB5BJv9vNoMD2dhSU0cYbq/Ugwi1HjIcyWeuaadKOBMOJQ178bXhvIp\nty8OedZEwwclrtLijO2Bfzk3ZfJv65xiXkq8z9+nAC5oDPr6b0aFd/34t50R\nT8fydofdi5bpGmb7okk1IPOtJD3veJqja1o5PNkuCYBlC8uV1kFV8akG+JqM\nw3KBYz19QLl5X3/2cU4/GVKkIiom2abhZAZLiZkDeJw2P50mgP1tWiViahcw\neFW7rpPimZsP7cXxzA+2U0Lke4EKDiguUvmBs4WVUh0x0zG8hvdCHpjtyMjA\nlPAHdHIfcb6btyNgS2qF/3dPS9L2n1IAf3omgcXmGy9IiUrvgYtMpJ/46Bd4\nhDwe+HUrW2T5Y4ciB700R6FXRTiAiO4wivOC/Vyz94IeustxiHDXmdYaT7mF\nTgXH2ksLHw6U0aLSyU8zQBv/tzrydG42b4GCyWDIkyDskbwKz7kd7CaaIQjo\n6nJfKFKpwjTybysoN/LlwdHqHkSDJdpiIwuNanwqW9A/XU5Xrcg06Sh+Loir\nv1jMn2Qq6mZptl9tGJFMuMbsu0rB3LvW9mpJOeyAVuPhJVGJaw2RzmYnk4+i\nzY12cp+F5iU+2ORnnrK0Wu+tqkLPfVtKLzW5s37s3ohnW/Alsr8i06imyXXp\nJlHp\r\n=UubD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC5xqtJ4AZ+AkytpXn9Dt6Lsh1YqGudOzDa2Cu6QkjWCgIgfSwZe4nzVJqH5RyUPylPGJVCMP8Q8h0A01OqOM7KF74="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1618631004.0_1618631013124_0.5919356835615286"},"_hasShrinkwrap":false},"1.7.1-canary.1618783411.0":{"name":"@joist/component","version":"1.7.1-canary.1618783411.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1618783411.0+2c67815"},"gitHead":"2c678152ecd81096bf9334a5bf9e4c7d56ff70ba","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { withInjector, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends withInjector(HTMLElement) {\n  @get(FooService)\n  public foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1618783411.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-eT7CIzylezl7eC0XeUpUykfRL946LnhRBZxezXuNi3sqnNvPpP7NYnDbwTDM80+X6r/iMIIx3+lpRSfJuuDCAA==","shasum":"94b99f4e35ddcd73701d6b8b61c7e98e3257fb60","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1618783411.0.tgz","fileCount":35,"unpackedSize":46230,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgfKy+CRA9TVsSAnZWagAARhIP+wRTu+ShdDz+4I0PGlRr\nNaBHO+oFYGdHNOv3Z0YJNm+a6wUg/i+/96bPhnGE8F5I8Lhax/1/IYEOiW37\nnA4twRQiXHL7EDFhj4GdKbZAe/KKuEZ5RTXNNmzi2VPKxM6RqM3HyVqlykF+\nykNMV2mzMQsOvb+KcbVtPQ9WwNWPbGeNQragP5Zjxwy53kq1IlVkegIcESRx\nKf5q2iF869xujFYZInjPqQXo74+ZYNxQwElx3sCrfaGB7o2EsGAnSou8HpGt\nqghlzk15rWsDQKDs7TDHffxRMF4xERZkxoCtdneowZibk0ESGwys4B992s8S\n/7BfqUdng8I7AxGK13fiZr4JgqtNGBPwgAUeJ9dvlLuoTn7/Psndxej159Bi\nc8MH+HGqFvxJTCYmtjpKASDgPTrv4wcPGVj6lEszlOYkwX1XWuWSNEpMUw5v\nIBiyl3ygdDE0zrDxVvoX5srn3eT7n7fmeiXsi2ir8h1gceSNBf7TqAeZT/I4\nezo1lbR5pXlV0OsxB/jBAoiUlKj1DMlbEmCwvruNWd6UCL9Hun29B2foUhyt\nfsj/cFiKrg3OQ3c5bqn/beOMgwETtfFTaArursi8iBEoGR3E+iB7FZl2NM+k\nLDXhrODGAxqvjxvyb7Jp5+Cuzhk2+vOkglYy23d+UnmMFAKaQd2R59jwKqrX\nJ4R4\r\n=O/IN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDWBld3tEgINCtHg5fKjojpkWT1VEgAE77l5PWrKqNOnAiEA+NY8boW8pqpB5A53knGhjE04e+tSdfvXoozfkGKksUM="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1618783411.0_1618783421943_0.25731003024792254"},"_hasShrinkwrap":false},"1.7.1-canary.1619551582.0":{"name":"@joist/component","version":"1.7.1-canary.1619551582.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1619551582.0+96bb458"},"gitHead":"96bb45854bcc5ac75e03df856a524f85aab89768","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1619551582.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-kqCy344zErVh5hrdEXTg9xoSTp3MV73RRn7RYdwH/E4Z+VbtYwvwekJuSIZdjdEBcTSNA1nHNnBMaOKzZRIQQQ==","shasum":"c9e6718cb39bdb88ff4158dad8348ba31afeccb5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1619551582.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiGVpCRA9TVsSAnZWagAAonkP/j5uRG/5l9QwXne3iovR\nEXeGNslqCuQz8zzHFdQ2f7x4y15C/og5KAYAJwG1XhfE6zQ0RaKrn4hHSHaG\nNjTEelPs8p9xhKatKOqh/kvziWdVrf9ygZWhzOfFZ81DNxBCeWyfjJ+fYsId\nw4nsj5o9zLEhq5EAhs3w0z9V3DfV9Vsmz0iaSe594IYieaa6cyklE5PDg9Xn\nktx1tIcVN7uMSYCR0GloTjDchqmJmbrjmAufr+kdy1lUBd2lfJWMXJ5RRPhh\nHIzJnFulsPpvHRx/e4fpmL3FAqdFUFX+LKkVTNIHquW6Dgvs3tTD1kvQUCjA\nKZpj6tIivBfB5WDoHWBUvh7M0ugoj0Ov4AA2auFyv+Ly8Vsq3uKZXJMMwf7R\nLALMArsAvQIwjfeVlfirNu17WsdPE5HigFo6VDlL9hme23BZbXglh+DRZlbN\nGqQ39iKRurYKiHVEuFd9oxkxzl2VEUuTong7rtOc5pdZGv/RmU8/pKn5dtBc\nCC6oeM44kKXD0kqY2IDGc2xXtO8MhRTB8XlSlE7cpYjPq5vyAvtqIWc/wwHW\np7IHeqKL4K6OrMytV/9NO8pZgj6A42DgUoPvvj8STmiyXjyX/u7+8vRnlI1y\nyEIXF8Hbt7E+YIVDkM/Pi+aIN5IvKj7uggRVjZVOpyfazuiZkjIHEM7LlYQ/\nQdOw\r\n=DY/W\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCUQ20khDz/+EpZnd9ADhejjcpu9BvHOcsbKTkhKPACKQIhANnRi35qE7+MIY8/78CJ1nD1JWlJYD3nAFC7kggIZB7x"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1619551582.0_1619551593327_0.6452263160836509"},"_hasShrinkwrap":false},"1.8.1":{"name":"@joist/component","version":"1.8.1","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.1"},"gitHead":"cb172e6df5e22a022e39d95816d75adcc404952c","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.1","_nodeVersion":"14.16.0","_npmVersion":"lerna/3.22.1/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-b8oprKeJ1DANCZxumVFkQGt3vqV9d8eHyucsRGCOlgGPoVzRDNoIWzIAM8sAswAcBEniPTZuVbCUX1kcIxfJzA==","shasum":"e040bca61654aef37e9cf22d9c46f7050c2800b0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.1.tgz","fileCount":32,"unpackedSize":58216,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiGX7CRA9TVsSAnZWagAAwPgQAJd0iRjYLABN5p0U0fRX\ncNi25JrFTmwBvuCLnUe0xJRmwK5iTM9a/JIHYrSS1RCQ8aTCsEdTxy+lbh44\nemf5Fq4l0B4aJiuPReyCP3/ZdcCfIlSJi74L0dKoSY03u5hXK2kYTOkYWcMa\niHf9Ig/bi5jbMq21XRcnLJpjbxRJborKxSCWiHJEAinh19hTWMNf1rHOVw6r\nx/bHOfEFBzzfnGn6mYCFldARvvPEwTfyZ/U1eWX6R6BPifT9Xq8FZm6KMkka\n3d+QtEHUPWpcpINXHZzKjquAVuKowz0P8SsQMrCQzJvGZQ1IshTcfYnqHUJQ\n2y+fvaNaHif8smDlvgYJw2BBHMBDICDVrFYc+/rzQtMuqGTMOJI+DMvJniXr\nXcViWjd2ikg3Hy5szzt8yLiqtawdk1Im0V4dEl+eySZBY3HdyrFUxfWw+zRx\nBfliKr9dtlzk7XldOQ55jtnjh/IkaGza8jt57a9De/g3DwC1kkbyaAl6mS25\nHkppyDXBGp+PEUKJ2wCUUv/siJaGY5kj5HeCbfr5UatHBvJInucpwGkJhqjG\n8NFgpJFzWWo+y9S8haVSv0Yk/9oM9nBmKmp+VCBbqacUTBZXmnmgtVaNw+2j\nOkGVlJzb3HD2ncZ+mERul+x7wy4Ac0oQX3dMREEnsisg1qhG3q4xLVh/bfaW\nUvQs\r\n=BJmp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDs3fLgjPG1hJGRjBwclihA04ouUndbQXvBjDj2pkC8rQIhAPoPnuiolYAbkfwPmJEy5zbvfzsbVEJq9pef3bYiba67"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.1_1619551739040_0.01138779033602888"},"_hasShrinkwrap":false},"1.7.1-canary.1619551753.0":{"name":"@joist/component","version":"1.7.1-canary.1619551753.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1619551753.0+dac8b8d"},"gitHead":"dac8b8df5eb1087eb3653c9c42550db7a3b32779","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1619551753.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-t6OssANR8F+cXzFRyaGx0L2Sr/KPk8Wr7+1B/GqXNYHKW7lGeMM7RllFep04tIy1X58h57wSFQR2yho0M4XaOA==","shasum":"f0edc0bd9d8a13aea268bc669415fb8bedc80ac1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1619551753.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiGYUCRA9TVsSAnZWagAA1DAP/jRed4+ZkyAuM3dwzvTd\ngkNqVraQelokVCme/yPF3fsF47Q3fusO6XYSxyvTBfnxv1FhCFbiMvp2Udf1\n192PtXxDvS47I/aIzqilBcBeXj7tV4IPNnDie7pD/Z9t2Nm18Wm3pzo/3CCy\nUMfc2Ip5mA+2uLHs00EsEKGSdPM4fqePavmG+aYjixUgBJ2B2SRMx/FKSl8G\nypk4M5sZrh8ofO7rs7JbrdQEFEj9uMAi/rXFfY8xp0YlF2keFX0x3sQ0gqeW\nymn1BLybd1aZ2d+w4vRVKpT3BXdAo0TttpvmBsh1lyksD/CvhWQKIUo/hbXI\nj44Pl+OP8glOnvV8grzQTWYLoxmMRvQjvfX82AZODUyKNQ85ljwQwYmQIcrg\nIK9lKtupzGWquG9k92GAhKTKFFGE9JtWv7k51BYurh1hzOj2kZS2aTiQ/5bY\nQ6G309NuSrySoriWBTRjAnOhIUDjxmIGT7zssLQGHlQg3upQN3Oto6U7tVxw\n8SVuCQoy3t5+k87YWTVk9ey8hj91SVUou8v+dE1AOWqn66sZDQpy7Vod+U1m\nneoP5oAp5KUAZ82/NVEc2niPTSgARkkCHDxebK3Wb6I1mSA3CuJ3qxE1PW7F\nrjn4mrl4hJs/He7T9tf1j+COODU0pC4rGOafHYQGM9s7zanaUfwI91Gv20Qd\nCTew\r\n=lrcm\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIF2klzQWTMgWkNfuAQBZ4GUS5Di4WCaTFjDcmuq0P4ykAiBcHh/BIa6B64YbZGW+b3MAJ+fs3fmYyErfhbGuvOniqw=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1619551753.0_1619551764211_0.9797732276723436"},"_hasShrinkwrap":false},"1.7.1-canary.1619551780.0":{"name":"@joist/component","version":"1.7.1-canary.1619551780.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.7.1-canary.1619551780.0+1e1486c"},"gitHead":"1e1486c67f363d5745715567f1d68b32e9b266bd","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.7.1-canary.1619551780.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-fIurqmMfVLA/LFY8dMqbNe42LwUD0tI14rdo8lvKTbmDA8jN0WbvonrHhHWU+EHQ/uOG47rQ6zsy9p8dvx4cUw==","shasum":"ea397f6a83fe742f6a482b042b04ac3366336e1c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.7.1-canary.1619551780.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiGYvCRA9TVsSAnZWagAAtt8QAI1NxQW4dRYAJtsWOEXo\nufvLAoW7AEmT1kYjvXi2kS1KEppt3kQRv1xETscPHrjgf+6iceUdnHyqkaIQ\nUuyPWpxYdFZDL09ZAGRBDlqwOZc1scMeCAU+pxIdwfcbJcEAWFRKq1bLJB5E\nmwi5An19BH1RsE9VJ4w++gtafF7ER6hWGhFqA44Ou18nnabvX7ZMqbH9Liem\nRSw70EIYJ4wlD3gV98tgPUU4wZ9ZC6dZp5XEg9l/sWDixNVhrgk+TqLZPGxq\n3cWpBkgX7nbJvDl9yWP+6JdXwyDoR0m4vyQ1jBQ8X4EDeCiJ/DtLII72rqJm\nURnbUYcsfGkc6cv59GxVBT/hHVWBPWSN2JgCBM23lBBjhrfl/4hc1dG6h4Pt\n8SLeAD71P7nkPkJhLp4awxItDatscrrYjt5yD+WWtwbX4XNvyzXe+p2WpQ+h\nLTYmv6uEJ2tqOSrIEQUKPF0Z7z2+cK0+5Tg1J3QnUEN8DZwoQ9YHQF+KR05C\nn3F4N4/fvcxizx1N7Ds9mJCPnsZAVve19u8Cpj5SWfJCyIcCfyjPCEzZfKW6\n9khrfSbTs1aZgc7jqf3AI5/dVnkh4GGIC8ix9ATRgyJ8PwZXaRjQNCqYeRyP\nEwyUfcm7fR52ie3fIuwScMPN3+lYSHC7v6HPktA8Bq9Ce+Xxl4ulynHrr2W5\nIXUK\r\n=PbfH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIENphC6KUX5KWtsNHiCfbIi0DPeAZo8xo+1WdYhdiAQgAiBMfCrOtoLJaTSlgRhv2tkeUig5TjnP7JoUnS02YFdfjw=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.7.1-canary.1619551780.0_1619551791030_0.4539459974406861"},"_hasShrinkwrap":false},"1.8.0":{"name":"@joist/component","version":"1.8.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.0"},"gitHead":"faaba7a1a2368e378eb46779f83c88dd309a0185","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.0","_nodeVersion":"14.16.0","_npmVersion":"lerna/3.22.1/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-iVT58T/w6yRIr1+LqvqO1lJIYoo9GZKFydNiP8WWowDphydFwxD9GjLcLeoJBueqJ8iDnOBnq4UrPyoG2ty6uA==","shasum":"cbbccf2c14724a9b2a9b2fea5effc0e06a67abfe","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.0.tgz","fileCount":32,"unpackedSize":58216,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiGZhCRA9TVsSAnZWagAAPOIP/1cII26dqslqyMRhCcxa\nzbd+zFzDbMuB+ZNMk/ueO6u0eymmdcGj+H/7+jAkEwM5UUYA9qP5DOW0GB2U\n0boXppA2RL4H8jz+bNEynOfjXMqUFtDGQLJTcevHQg2nHq1Fbp4xVIDpCQ2m\nji4kXWO+svHXTQkyAgn1Xm4t8kY8H0ykVKQWQMe+yl7DGuzOy9eN9rNxOxJq\nPDkSpUhNlhEBcoo8E//0kTj7O1AEBGfQYozyjsVsNV8LTeryHxELa82tl2s6\nJ/rSKVpX2zTLKzispko9CXkCk0nH+8UGrho2xQmMHUOkHuRylatU32l89aT+\nFo6VD9QakPAiLztOGqi+FfwsoxjewBOW8kHoHojt3Z9nwtP+n1+GgrNpABfa\nVt8QOL9jMKfyrcNNEE26uKZpN2F5djBJzHO2F+gwMLXpPvx/YL2sUc1ErVn7\n9PX3Zxr0jiMRz1rhFRJbpRLoRHvo9Kic6kfePpR0jNBhvS0O6yjeBYbduNLM\nsF7yrw+e0k5wErFOzDySp5bUERactkHBG+Ad4jc/Id/FwWRBHGgq50cInHPt\nt4/mqaKOY1unsz96csSCfw6THZFM4K1k6jGVC132hvrbI3s0cCqL3VWu3AH0\nXsevNn+syopVzRUgkiWE41Fm+A0OBCEjB+UPcg2NnQyNfU/qm77V3XC7ndkE\nRTaF\r\n=IvVp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDBAc344OWjg8QGHYD4B9lShoyEPwaYNFnpo6mIhNGEgwIgYZJbYq0H2wiTUgcpZpITUAARBLPFGcXVk3h+N1mYP/A="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.0_1619551840819_0.22381841189651452"},"_hasShrinkwrap":false},"1.8.2":{"name":"@joist/component","version":"1.8.2","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.2"},"gitHead":"7f40ebd585a1d1ea0f113f9c1bd7aedc2d8178d9","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.2","_nodeVersion":"14.16.0","_npmVersion":"lerna/3.22.1/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-e9BsllI1TyYUA+0KSU9zksA7an7MuaYgxFtukbkpv0MTHcxy9JXFTHSxzZWjvQSd41pba3ws/nzyEwAlJobbew==","shasum":"ad1c2ecbd54f4b51f95881c2e986b18faa6eef79","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.2.tgz","fileCount":32,"unpackedSize":58216,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiGaBCRA9TVsSAnZWagAAabIP/0F/WfdjFZIYDxMOk5gN\nh9jdQzIs+vDiIiZbcKWzp1/uZOgj8wrk0RzMcKPtqq6gFTm1SmFQ8kIS8CFV\nk9vbqNaqwNRHITOzgNPB0UPVHq7qAiIRjb3yiGh/H8kQjhiYvqW+b1tSsZoC\nAjuPmqNRm1Bl3j3WOIPOFIVw+HITIEo60Wv/e0g2j5slYUnR6ovdVuoDYkia\nErinb7HV+Xn3XHOGWKSdzAVfyFfFLgzipc1rxYNld5DoZ9nzwoPVoM1V3/Ly\n6GjbVOgu6X23hMncRdFSQRHp1Iz0S/i6uS6gXzefulMQ/qfwKWd9DCZvD0Lk\nCxs1S/GfSwfE3+Je7cXLQegjb8m7Ef9C+hjmP5e89v0/0bFxBX0UFDAa3KCU\nBVuXIf0b4HDDPpRUfGlyqwyN42izsE2I106nN3TOk4b/DvGaiNvI+RysZcFD\ngl0woYG/3OxntrE8i2QbLclzef5c9iynocRvw6HolsH66FnmiJTHcYiGK1+C\nBPp+erKHRwMO7HwgKbFRyOIiydqrc3sKM0Y1vqdx1tj011JHbn4LtiwexvDi\nCv0ZHdyYNoXMOWIi6UZ1IfPqGLF+kVt1fShouMRONS3Rc1NUs+n1V9Yh8mB8\nhalwLaYxj5xQ0tz9cuS2OAtmEr97yCKnosU28mxcpRAhqPVySddKuC5RxJRQ\n80PY\r\n=v6k2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDzarMiMNDW7axEkF0VLXwSbgf9SswOC1hJF8fo/ajSUwIgQAhTxE9dmGPvBgOrhRIE3SaGzyV3W7e14Suo9Q3pMaI="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.2_1619551873003_0.048951095793331234"},"_hasShrinkwrap":false},"1.8.1-canary.1619551931.0":{"name":"@joist/component","version":"1.8.1-canary.1619551931.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.1-canary.1619551931.0+faaba7a"},"gitHead":"faaba7a1a2368e378eb46779f83c88dd309a0185","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.1-canary.1619551931.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-LCNU5uCfpLB1eTS0gscoS+dW6/0SOen0kWm5GBDkh7ZUWsUI1KwWjw3nQ21cuj8UvdQ3s9NXrvfXPie4vQY6rA==","shasum":"3981c1f4a6904b4c8a87ac8e474b019f33d33a6b","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.1-canary.1619551931.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiGbGCRA9TVsSAnZWagAAeEoP+wU0RTRAcmH2MK12XpzY\nOaNy4C75TXpYaZ+G3v7SKh4Hqtp9zPyPsNJ7w0885wD/aPsBU+ovLlAgy7cO\nHbGhb8VIv0LS4SF8LlZLIj1w/zM4LWd3mA10jltxyqoSfLGdo/829dzto5oT\nwpMIbqZ+YJcRPHtsxGM3hA7zWB3PONnmCfuCXckrSJtVMGHH9IP0zar6NXYs\nFDHjmz0gGDtTChSJGl52YBvV8nW00eFW1UMj3dCoksUG4/aGot4ruo9ldFDa\nUPklENA0VjrXDFweF3hq6U9yHcsWD60WE6SanLpCcpdm6t/OK6hEQ94fTdjD\n/5FGuQImUvUgxkbWf/w+Y3KxrFRQauGraK3DGnWnU9H3ypdGGNFr2MVJKnQ9\n3GVjQ4z0Nz9qb8hQmkc9xru4bitUrVzJNFuCDf2X5MVFwYXPT21s574COR0q\ndmAXnjpscsB8JwBil0833jQ7IM8o5r1lwpHeGIwOwcjJUpACerQYqMPn5opd\n9UyOocnfuKJuC3nn23JUbgtytmQb7R+25fBhA44RW3aoZLAoZQRj+vVz6wCQ\nsbl2dNsQb0AWOTNbTPJ8dDbFdoQ5UB6QH5uWEK938d9QaAmeUZzcuqhpWZFN\nQTFOIvWGoorMJW6qja3tQ0girM132XkSI+wqjJbfHDu9rBiHc2EMT9bazyP2\nmshR\r\n=LDEH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCpBdJMq0gt0PcwyXwCYmllXczV+sHGLNSoyNB6ijiexwIhAM2tSpx6UcKbB4mBJQ/LKk/DImM+V42ljbuYnjHxp3oR"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.1-canary.1619551931.0_1619551942056_0.9847690721186151"},"_hasShrinkwrap":false},"1.8.3-canary.1619551982.0":{"name":"@joist/component","version":"1.8.3-canary.1619551982.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.3-canary.1619551982.0+7f40ebd"},"gitHead":"7f40ebd585a1d1ea0f113f9c1bd7aedc2d8178d9","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.3-canary.1619551982.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-qsIFJK/qgBjaOp0JSqFFJ1UV6mEzSgZ0B2LhauhtirV/CVEOk44i1XZfAXp6k+RtEtowNNP6O++JrMOn1jeA0g==","shasum":"9428d4819c138339c68ea2ee8afe2c6a6649cfb6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.3-canary.1619551982.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiGb6CRA9TVsSAnZWagAARccQAJLfqMr9Z6Xpq1me1XF9\n7hMqhff/9d9l843X/x8D3fk1rTwq5FI9/kCPr1HIE2MlwhDkDYXPet2dXM2J\niyyI43cnuZErXisS96kGAZhF1TrlHeeMVeqWL6+Ce3CcNsHUc9Ivh4hGHMGw\nuC37L2jfRcSFq9hdNFPvF+y/mDLwfFLJiXhpNyiVxs2plRyhppQTHLD8jAHu\neJKbmHwfmxIhPnrzJMmwOvVqTV6ZJOstc5Im2sR3CWMrpErv9v1IpT+y7Sh+\noDcHK7y0AnVXFLiNDyM2drW0sc7iZarmufr77vVCFBRbljXq8Va/WPS16oHT\n/ldiX94Ash0I3yO+xWLAlSYvXVylthHCOvAMIEARw3ODzIsbupZvr1v+3+g9\nbc3S5p8xoYMMYtbGiz3aOf4m9shEHJEs5ZXy/Ay11nDbOMTNOcHV+VFOYrzY\ntQM1v5BnL0M7KEAxRSnCaYSnJAHJ7wIDhw9sQRWskdB+Y2db3Vu/hclPaNFB\nHhQMlaGIzNWgUAL9nvt6ShEg2bw0vysiWIBs44R3+EPSJoBsOV2bEQJwJFra\nA1j9mdeGK+7TtU/6y1TAqEi8v8JKz1iaT/4Ud/cGhIxmdRTSJoFJLD7oSax/\nW0oaeQ99w/W1ZPwX9iNsB1JuBSfrFRSHos5LPq9QYiKCEhcM5rOI05eWR5vA\novfi\r\n=gbLw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID/PRZfAMJZvT2heVu3SEvbT8XndPUBnMljazzOJFmmvAiEAxusle4ZnlCyo7lhxhy1xxp9D8LzOToD1GUe6DLKGkE4="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.3-canary.1619551982.0_1619551994334_0.26507159153581017"},"_hasShrinkwrap":false},"1.8.3-canary.1619554665.0":{"name":"@joist/component","version":"1.8.3-canary.1619554665.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.3-canary.1619554665.0+a84657b"},"gitHead":"a84657b00c52d7baa25725a7f6737818034e37b5","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.3-canary.1619554665.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-beuVb02fsgb1wrosZPmfEkbvK+i1xNTTKgspDsRBeISnEMWn2m6wcolmrnRKdl0WwpNwku1kWWEgCv9qFV2xQg==","shasum":"e10e30e8404bd4b2d2fe08288bf9d92a0221201d","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.3-canary.1619554665.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiHF2CRA9TVsSAnZWagAA9DcP/10k5Wm5ytxHmeOF0X7S\ncwbbhK/gSREcvlE9t7eLfjfeVFlnLnDS/6WeNmaq4MZx7whCdw2GZaiTcOT9\nsqgxX/I5xPuZvT97QE9Gr+yKmGEHDFfbUlQEuDnxYU0cy3IchbMDoAHKJGgC\ng2e+0gdktx6lYDOfxI4m+TaxPagwNQOp7TRSejWOcZsmAdXU2a3kz+/Iys1E\nDim5mjdJsnrvHUaAp4cjU7aGHK/VN6t8G8P5wFW2iXDgFMe8NnD0WSFeS7mU\neb0+7oplG68lnaHTxETezgP59ANJE2IwswTDsfXy0cX1DqMddcYCOj4T6gou\njGrxX/zJEHEUUFHGIQ4ES0yp/eZz9MapejjvnWtYHITHTUQx9YH80lpvp42B\nQkcFbHz5ed6jHnp3GRfZCHIFJTg/TNPXh7fJIwdOqxfyv7ZztN3pXluO+hrB\n3ojRkqDj6LUYZIjF0xrEXq7vQs5U10SqdK1LIDMQS8WLmOFEjw8l7Vf5mOCI\nxNVDHyu7+E6mBN5g11UzXh6UPDdi1kQabp4h/I3/1zwEvAPRamkzU3NPfEy0\n6ZW6Cfan/Krf1vo2AORvOebuioHQ4I0g3J2OZKNKf0MnX6gwORuxiZKQ4iGz\nO4UP06jZItaiLV+ssHiqj9iG8zR5LzMTqAvQhow/a3LFCEU5qzbI76u0wUVU\n9nEz\r\n=lh+z\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDNrWHiwytqZEZhv6CovF62iMGNtl7Wz23nGPc1tbZqUwIhAOX77PCT7bGhPBAF1EDbzZzFbfTLpXBRedVCvI4uXTcS"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.3-canary.1619554665.0_1619554678509_0.7404542812386077"},"_hasShrinkwrap":false},"1.8.3":{"name":"@joist/component","version":"1.8.3","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.3"},"gitHead":"52f7d3f8bfce260e25b4f09c282e9e114aac9dba","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.3","_nodeVersion":"14.16.0","_npmVersion":"lerna/3.22.1/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-VZM/ypDD0v0DGtQ3EGyraDzNkM/KEzSnF7nel1GjNX6KPFP/2wvdYWy1FeZeGj31Udo/p9KYJ7McAZzATgFzJg==","shasum":"f07605d76a01088504df72d4914dcdb56babd4eb","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.3.tgz","fileCount":32,"unpackedSize":58216,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiHGcCRA9TVsSAnZWagAA3wYP/2fdGAj4mYCJNjNeVjwG\nztpX1UWQajDusUguEWLWj4hfcS1mTD3CC4BagC/Ffv7+lsBbk/QiTVTUCRaj\nfDfmAPCqsScWwbM666mFvLn35YgkM2pNb8k6ixkLePmjFs5kZpzgPw5h6JOb\nIpHjuo16ZtgTmQVt+ghgceFMAwKamD3cXeICDqMWOyefKm4HJol6nMP8nXFW\n6zEXPHsx8MbrJrnwdF5SrwRTzs2scB+VLlcyUl48BmuK0P+SBAvZdvVEVwhE\nfmK51qeBgkrm0jiy5lmhgkVbUeV6qaxxGjfIs3ATNJaiCRUCnWwmymzHu09B\nv0qFAADQU6GfsA8AU0sz0cDWNI4qfii+6vI9Zhq6U6kjctvZ9kg5H4QwAOid\nzyGOVovrnvD4oKJTVftvGrKy2SePmqMSzlxG3pkNZpT/KZFfayc0XfEy4Sz/\nxe3nkP/9kC/pwUjq9ddxbAExXpmG0eB3rlXkCMCdxwyJU/hSXG/b9oNQ5Euv\nrITZbG+E5+S49Vu7ZywG3iyyfJOdMp27Cg3xpXUDkqFnqSFXBgG0DIpRR9LU\nM0o00GXwRXBXvrwmnokl7ID68Tm6ojfosTG/4Ij/edFHH7GwIZL7aJ6w+DL9\nuiZKEmW3TMhSj1fEhT4m6A21tG0imkwgbUyPNqd4TvBcA+ju7in0YJ12l0o6\n2kV4\r\n=KQfG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDsccvSFrwodwUfQwOmyF5p3TuCpfOQycWYblYYpIddHAiAgHb1OVOBFEO2CPCPNNNhce61URulJBxZGhc72kfMktw=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.3_1619554715887_0.20290205560625418"},"_hasShrinkwrap":false},"1.8.4-canary.1619554801.0":{"name":"@joist/component","version":"1.8.4-canary.1619554801.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.4-canary.1619554801.0+52f7d3f"},"gitHead":"52f7d3f8bfce260e25b4f09c282e9e114aac9dba","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.4-canary.1619554801.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-kIaeyx8oovhC5MU75IAwTF4x+YcytKcoc8N5hCXyNjWE7B6MR2O11mbazQOddywdSibuV3++NT3U+jDODJ1O+g==","shasum":"235dcc79876add9bea63a647e26a0a0cb88f6f1c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.4-canary.1619554801.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiHH8CRA9TVsSAnZWagAAHAYP/iIB58E99BB1Vql1suwO\nuA3i7P72Ir6pt5+3WX+V9V6uRCz7CrkJroRFhUgj6Scd7WPjFpcfQiUuhGZg\nHj9Aj0rqBgpR8QutyzHmTWxfQ/w/Hj83HjpMISNfdoyk5TIcH0GaqITJhnMp\ntTlchdC7QC1kc/G+SWOWrNX5eP12QMdRP96OcYb56C18xSM2hvDCj5bJFWDN\nNQPB10r1rZyc7wD20MgfwtmSIVhP9Lu99uZ8dMYWsjxjm7pfIJXIrE24t/fb\noWwPr1Mbaq94+jpzd4VNZG6+CPDcGNqazlu1yl0lXYq+m+9xK0z0Yv/fT9OU\n1ynW0bdU69ErRxX0mIIVdsF9b6log2q1xypfkbfooinke+jWMkBeLrTcLhj+\nMtTLrZAphOh0aAGJKKv8t7nbj7f3KVqYCX+c6C0xnfyHJUqo40/3Vja4gd4Z\nBPwix28kBaDm5RW0vQJfet5aBc690HoDHNKmLdDrXNFcT2LFLAUp1+OQ7RuG\nOXqx0437ayuLt7iCJ6yA8fYqjCViVYuuJBo2x4IoxYP10STJp7XkIDz9Tr9C\nvZzSIbhlUCGSomvce/zll6uKSyXjgwHvFkyTzSHiRIr4Llvvu5ymFT6L4CRs\nUND3rsylM9gjuUqYrSH/abcXgmnX+N2rRjLlV5A5FhsF9cOrv9+5Jt1WZNVl\nEclL\r\n=D7SN\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIB7KRDrLBFoHojr6cryXBPoKnJJXTiEBj/WLX6WJE8brAiA/icy1WCQtD2ZOtDFQeybBJLuOMcf/VZEsKZv8znpU1Q=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.4-canary.1619554801.0_1619554812015_0.8372362667686513"},"_hasShrinkwrap":false},"1.8.4-canary.1619555984.0":{"name":"@joist/component","version":"1.8.4-canary.1619555984.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.4-canary.1619555984.0+30875a8"},"gitHead":"30875a8a95b3847a0a3e75390bae2bc42fb78c77","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.4-canary.1619555984.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-AhTOR25rl8R0ci725mm9BAFTa2aPYRTsxLs+5pI9AMoK3tV7SNTuZjyIPX58CTextjJb9f5icL8TNUsbPpjgvg==","shasum":"90f77c022c9055833d76be3948cdc1026c79f4ee","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.4-canary.1619555984.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiHacCRA9TVsSAnZWagAA39IP/RvxwfavVRxDnfCElm/v\nTp9zATcSSF8EVCD+Hk/S27RfRFBQ56T/pi7a1ZH07mwdu7pw9qs4f+GXF64o\nZ6oOkHPbnsYpQVNsj56pOu5N6XHWpD2t3jmzQivkeg8HMcz+4vKO/tR0lda8\nDnX0Tzgq8amW621gzOy+11XDRjRqdQOlvZKSYhfAXpk1ooJMagzOdMYsoo8m\nCklV6KoCKSF2OTvBPU6t8YoxvxNSGLo3UZnqM7n2I+eARe/LgT1/EEr/5jU+\nFqxr/WAhxfw7YLsKiuZrMPgTUq1w0TZZpbtAS77kDwb3cNZRUsK6IuVo1HcN\nxaYNmes1rnOqpBaQQrPpEutHzgiupJGFS9G/SnTpuEofuca8PHS1dSRtMrzi\n9oEMkhIgjH4kO5kuRZG7nl0nxiiEwe19R6dnw3RP2V31CEv3jmAWQqf/QjU0\nRft458453ei0wIeE2CXXLUnChcgT8vSXfyFzqPK8q1x0qXUsVLj/Dfe3pYEp\nGfK89H6B7ATD2HUAgbjKhlb01s0tQTZ0c1QTQffEgy7DJ7Wvv6rmC8WKZHG8\nNCBpoxZrfV3OqdGLL5v8+s532D0dsR9ogSLseV1au7n/8oi8AhBgRjCAnw6W\ntEExBCfGYwX8gH7FnYze1P49DPzUey5E80du0Ko2hsEcManYprBoqYZpbNXl\nhi8E\r\n=8slv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEP/k8eELiLAK/6ToT2CSsYKiCCJ6SgFWegwoJR3Ie8NAiEAnsaTUeBMsZ1n7RoRxM7GtLfjxXjc5aVdwkp4hdRuOdk="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.4-canary.1619555984.0_1619555996336_0.022145136372335283"},"_hasShrinkwrap":false},"1.8.4-canary.1619555999.0":{"name":"@joist/component","version":"1.8.4-canary.1619555999.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.4-canary.1619555999.0+db451c8"},"gitHead":"db451c89b7cd79b3f19b49b16bfde53865780632","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.4-canary.1619555999.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-J9zxn2t2FNaxWz8lEuCWfgxwA76uog2vwEuva62c/tkfx25nQitkUHa7HUGUNXtLigyx1bozsyMLBsE5sVG7kw==","shasum":"f0d2b0ceb68e66e6e7f6a3b93a5cda73c7d6481e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.4-canary.1619555999.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiHaqCRA9TVsSAnZWagAA8yQP/1lnChNe6gyS4QjCAiDd\nFAAPW2lB9tKS+RvRBt+lDEIOeN6JlVl01lOgOgnkhnUgBVwkgoRayhO5boWY\nRlVetMItZwSv1Fq0Ug0EihAXI9QWftkMPM9NHG2/yF0A3s27QDrD2mpQ4LnD\nXq2XXFCrsD146snllPETmrWdvMaVy8jI8SsyBsD45HlysdXXbgv8gpaYNnDe\nSEOY09Ynj/Hv2eJVh+2FI9RM8hKfj8hBIINULqThipVnoLQFsp/vb9pIFlJb\nhnJqHr0QG0RdM3L7rYb8SWUFb87b9O367txQS7FHzfh9+JwSH5QD6VwETN+l\ncwhHjua53WosDTTm0IxlTqVW6hjR3itcxeTeSbD7epUP0tAdQcsik1th/Oxi\neAna/uX/VXEzXNKh0B0+rroRxCNAbWA9Q4wS7QWEbd0ZkE33d6NKmA3yKG8S\nrlA/Qo5+wMmxNN+zrtl1nRVse8Q12o0KCNWTTvXXhmkKWJrIQsNrtdHyyUKv\nnXkJ7jorO/M8tnoVeoWpE1moSZ4zH/wZPxh1W88ZHQbUqhfd18bUKRgsu9/3\nlvdlMNH55PQZWrKAcWvw9Sr+1ckDXX2rDVkYy9pwa8IpcRBLQnPCC1n+0HOb\nm1wQCrYz92TgQZEgKq8DY6Snsvp7q4ZOR/TwFwwfbn24+sDXOEKAQ03hD7gY\nV4WL\r\n=qvfS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDYIPV5t8l86PhoNyeHMRnwhQ/vYpPvz8fvo56vCwz70AIgbJymSz/O6idlXuE5oo+a+EsT05me6Em+T+wZJq2y5h4="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.4-canary.1619555999.0_1619556009531_0.6724412849273276"},"_hasShrinkwrap":false},"1.8.4-canary.1619556102.0":{"name":"@joist/component","version":"1.8.4-canary.1619556102.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.4-canary.1619556102.0+e784a9a"},"gitHead":"e784a9a42288f37b97ebbcd6f756de817b1f2f8b","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.4-canary.1619556102.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-5W78aoq+WJXTHSMHZsQhrreNHH4SbalZkRfKg1/AEY296NRAmW8OBGfxE5TD8phQ7MWtO6bLJc8ucPQrQJeVlw==","shasum":"cb3c84850d4c9d842ec5a024c9f55b29e4bd2077","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.4-canary.1619556102.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiHcRCRA9TVsSAnZWagAAYCwP/15F27R7/ZMag5U20eAX\nF5BL9ElFXvzAo8Ox4zvu1+LG5L4J0/JprDlK4mARUEeoMUgdYrzsseYwMZ3o\nnJheIUPv7mYwwVVC75rT5xaKCG7i5h772CJv4f/DJmssRgKBoEg8YwCLHtyA\njtpXIdwQz5ISHyc17Ck89IIGOTmuiL3nR542VsOquanvxL3+r5g591l8Vzvi\nvGJnCiqnUmbwv9yrxkHL8t3EFMt3WnoGfPVBv3cOOhPbeZXTKdcqWtDTPWuN\n2cZcnZsW/urBI2IjG8W5mKHz4SQiawd2fijmnKCa1P7nAAvL8J5ZpyTOBizt\nPZw0jMfvlesKeo3/f7D6tzpw576KTEntuCkDuugwLjU9LGlJGdpcjF5/Ke+q\nB70LJ7/z6Hn22bldpU6cEnLYWCaLzI/L+apv9xiJ2qOtgwoDQYuBQxrTgwI4\nOF+UlpWV7VMOCtLQXFZc786MkEHZOGhtcH9C73c09kc8N7UeridMrJEJYoEM\nFPV1fX8XyRGnkxq8CF4m9sA6VSgamn6y61a9y13qfAARXWk52XBi9bYgEOKV\nOjVkT2AFxegBCkVaACpC5KQ5+Yyrd3LPe4j+Acm0jmvn/DNdLDAB4iKdXtJV\nCgG2aIaLwT5YbHcr4iX4eGotA1KQGjVrZtPaz4xafbIRBec20Soz5SgPCoDZ\niglK\r\n=nwyY\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEqclUYPM+iX/8cMpsD4Klgq5whgWLK+rUpZg2xmeUXOAiEA1r0QJf+2yt3jg99oEyFndK2sQA+Da+p/rPAVpp4guDU="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.4-canary.1619556102.0_1619556112707_0.8294396911076118"},"_hasShrinkwrap":false},"1.8.4-canary.1619556550.0":{"name":"@joist/component","version":"1.8.4-canary.1619556550.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.4-canary.1619556550.0+6a44a79"},"gitHead":"6a44a79f013c5c6efbbedc07e722036d608abe3f","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.4-canary.1619556550.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-a3/dnDg27NFL+uO2k7InCS8zoHBuM3ogENTeUQvHlNGo46neVTDsKpY5lpQ4gj3/Jt0x/JbdoF5MwJdd6Rl12Q==","shasum":"adfb4e4736c1e48dfeb3414b06ea96e6e139f63e","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.4-canary.1619556550.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiHjQCRA9TVsSAnZWagAApU0P+QAW1WL7SEqgp1PT8tsL\nLf8BPNY37PJlWWDBCTwsGNqcC+XreH5PqfGmtemb9jjCyp4o0B/qIlROz7ze\n+bf5D3wV6/Ps6o8wldut2uvG8KdL5/R8x+l3IV15tYUP6MfXY2IRY7InkAbu\nk9rhL0SQ9V33TZp0ejThaiFgabhIeQY+Mqxb8TYw9WMVNh2749V38IjAbFI9\nWyNktN6z+7jt58T3di3hHzd02IGHL22LxDiUFhSgpiqDF/r2uaTnRBlpWAoE\npwV8M2CrOLQr1zorQi8b/+tx+tVrYwoN/A10yt967C3o/Zff0+xUVoDcrMNp\n1eoCCezGaNDZI+RDXzl+6tw3cBSnk+3Bwxl8klbJ1BJWz40ACJt9sh+ERur6\nXZ9kAYWjmY9ABxkoUT7h6A31drfhfPkvtj0AjFcjUX+dWdinHTm/2aXQAFPR\nEu8HL3LVJRuDis1AUnbKuV5rdn+W4dgu6vS9Lu9Qeww5yHY3Mlutn/T9HLym\nU/hNaeJ/IFa06Y7PPfJdqE4eJaQanVdLl/zamXhJE4CyheRgqN0pJ/Tf3EAV\n48Sh0KKKLs5PZlyOs54Zplfe/EmMyybGgpt2sLLWtLDtxU/E/G4GYeD3tgVC\nd53QRZvB/IwXZL2h13JYW/09Qu2HDQzOH4gmgG7ltmllYQlwrbOuEt/ieFWb\nx7yt\r\n=x4Ei\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD/vsKxEa8FjwmNfHUR/RMHi/65UYdw669ww74WoWkanwIhAIZXhdNmsbhBvC8jN/88VmQmhrxoHGkkioZ2Pr2D/hco"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.4-canary.1619556550.0_1619556559982_0.12614687310237938"},"_hasShrinkwrap":false},"1.8.4-canary.1619556662.0":{"name":"@joist/component","version":"1.8.4-canary.1619556662.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.4-canary.1619556662.0+965e4a8"},"gitHead":"965e4a8928f313979e4e39b3d806f9f6e57f2c00","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.4-canary.1619556662.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-Twce8PTA3Chepq/u+wgzxMGCTH/oqZM5VgshQY6iCgNy52RDsmz5IuJT6DJ3XjkFIpGW0esstZw8vQCthn5YUg==","shasum":"b58988559ec685ae4a1da9959003fe159be377aa","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.4-canary.1619556662.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgiHlCCRA9TVsSAnZWagAAY9AP/2k48AzD23fIWXcI8XZY\nJodOTfWBm6vjYPzPiXEcfqNXz7G9S5kHB9o4fFIfSI4Ao/HAoP+WeZDbOx7x\nAPkJsNq+GNL3iYcPn6nGDyPZFaRZo1NUJ4HEYg8+WOvKjMoucdqmRP1nNlKT\nr/O9jjyS4YeftOgDBPgsoXqTSl/kQxUlD3QyBfcnj4qjYGRDV9lwFaMDzjTm\nkMcEnWzVycg58oHRncfi8/K9xplkznI+aiqQ8pSC1/GQeHvG7p2Bd6HoA9Tt\n3jV2EQxXYbe5FQcnR3sdBRjW481K3PcxVXGYf2qbcHjD3X2TCi8xslLDeZLj\nRO1aawfJCP7VfAOiVN1NSpRMBgQ4ahLBQlFNgYqEAsvWxKLJC4IVdJaX12BD\npEtTHUDHpPohltdkcijVkZLgZo7S2ngPDAK9jbIk2FSLPVnTonJT9stXh18Y\npv3kbYxm/iq9SA7V4uY3XKY32omhMShCwEOQxc6+sej6MRbpyg5768UEEG4m\nXr2I/KiSsq/ww5iX9g/PTYC1JcjdcWNhc7gjh9HQz0h6UJKvPAEKSIFF4KsL\n6BKUVIV8gAW4mxj6NQRzlU2/zJh0E07VjjPO3mgu3lyNe4GR3jn3pGiBxeyx\n42NPSOIsFV6TdRWkfbOF+1nE9FWHkKJX6lysHRr6l8sboyxc3/Ez9rRwv6Ic\nXFvx\r\n=LFg1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCjhRiFbyCW6jg8qXlsIy6rpM61sQTKMR4GWyilegdYIAIhAKnEKQSsunsmF8+BC700T8BjDqB/QuKm7SPI+fAUb+sO"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.4-canary.1619556662.0_1619556673596_0.15262505569731633"},"_hasShrinkwrap":false},"1.8.4":{"name":"@joist/component","version":"1.8.4","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.4"},"gitHead":"69384c52ead6cef6d5d56899cc0d1db94acffbc7","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.4","_nodeVersion":"14.16.0","_npmVersion":"lerna/3.22.1/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-x/rSuPfzqC2MRQgLhZdHZy0PSsdHOkhPz3bQ8KvhaSmwK0dTeVkVw61sn/r8emunjgXnC0zm9tot394hIOO4og==","shasum":"655df87a173182f898b9d7db02c5f7b1eb545ef0","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.4.tgz","fileCount":32,"unpackedSize":58216,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgicTFCRA9TVsSAnZWagAAlN4P/Rnqx1hfABI8jXATGxF5\nu8zTn8fnXrlPOy+d5iIMvuAdwTek0TX7/2F6frc3lMDhjOwK7bHC4cFe0sXw\nq6jJCBQ5ZDu14rdTM5DCycSOivwA4BgtvuXXzNLbwfmZM75/0NonR1fv1Qqs\nUqz6t2NrIKuxQzr7m9h8M5IeWcUIwudgXzBJIrqRvDI8A49xys4MSjMydIPF\n4U6F9wTya0r0Owa0gQTGkmJhnwnqhNIPlC3fhlnC6ip0mPTHoTfxXakKYqy+\nC9Qx4jIRdpDkyIfv8m/urjTbGtH9PTJJv6SbSe0gQ0OQXVcmRBmQxfvMAN9d\nNW3Z6Y5snSul+4751NuIJG980uYJFGlceoU/wt4zY4YNxldlMffXQxaQo9mC\n1215gj9aWGx9XHEj4k2Mi7/LzEGl6Js5wNCYr3WK7UAJFKVG4gfqlP2eF2L+\nJQ05exn1flFdDLK+cFH8U8ibjZHR/XVCEnxWqZzcDWA4UlzbeqdSlW8L49wR\n8rT6XOIKUM+GCHCd3nBu+pymBDYoPG0gaDBrSG9YokRdWP2weIHf1i93cDBX\nayMsdc+FRa/v8ZAq6XZYvET0bti4BVO1upd2r9BLrnxx+X9lE11CoY4EwXPX\ncV7/y5CieQW4Cs10yBLfGPDoONS6Af5ofjd+r2eLzNizrLJKaFA4QMsmJ+jl\nrcd1\r\n=+vhA\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDllYFtzP32ADfYXij6rGwXnNIfkYrtWzpZnTsEsXaADgIgLbtfqDT2X/yyA2/TrWYEILUR+9XHswJZVldWDq5ndLY="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.4_1619641541328_0.4441808839958341"},"_hasShrinkwrap":false},"1.8.5-canary.1619641637.0":{"name":"@joist/component","version":"1.8.5-canary.1619641637.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.5-canary.1619641637.0+69384c5"},"gitHead":"69384c52ead6cef6d5d56899cc0d1db94acffbc7","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.5-canary.1619641637.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-LG9Jrv1SKl7dHz2bG01o5ZmY7pjWJPGNyG0ztfOQaGErzG47Oxy7hpo+kP6zLlnVEhRAzfLY6VtaWNovvYVyBA==","shasum":"7b3eb5a26231048fca50acb396a3ebf5963398b6","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.5-canary.1619641637.0.tgz","fileCount":32,"unpackedSize":58272,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgicUwCRA9TVsSAnZWagAAm/UP/2gyx8WEnUnhI+xboZM8\nW8XffQZn9a5w0YI6AwBLGf7uV9uMA9/LCdV5aW1BuHfoLrQNmuMlSLuhxIDS\nusC+3M7BAN0j2zjiu3oFHpOUtsOtzTBD1MkrO1opBA+CroHmju+D9nIYv2Bn\n4eRRwMnQvezKcmm/N8NeqlmsKlbtIMQNyA3mNdt9dt8l87gU7LHNkJSJnNfy\na36+AYqZkVtq7ISwavfK27/WgncEy/RQt6xn2nkHMGRjPWsJiowFi8t6jwII\nZhVZ7FBy+Zy9xOdZgqHWanAnbKsULREX9wwy/XOwyQlYsyL4599Ga3DAe3js\nv7ffpVvNgHj55nidj4Ws4f0YjTc3HKz5NuyzYCmmrHgVPO7t+0UrpwXvvmIV\nAU0kwztVsO6rTDDMF0nLuSz98Hw6b+q08WZOtaANjUODUicvl3VVlkzg7JFo\nPJwOcrfRUVm6qj51za5XWzwGNStdDGQqzpbfYe2KfM4kpjCTn/eW3hUG8PLd\npKTiv8Fa3ZlnXtqSZxRaDOy8uh3/eu4QWOl1I5iLbuUj97IfNjsmx7y6J4Ry\nYRloysFJaaDFZ9kGSUZdT97BxyUGbb2xC1tA4l1LZGKpM/wUDrEU9In1qtC3\naR9jauJRsZQeWBdPPLHuzslQRF3WIavnw62AwaxLLtlMuD8sTHZZ6rkGd+Eg\nK5BL\r\n=NtPS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC9/xDP9q+oLI7kTG/WdGO223B5lZD8IQ8qZ28Nqj0myAiAmg11jO0S2vvu3Bc7BL/D6zd+nHtY8VjbOYC9ukQwVcw=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.5-canary.1619641637.0_1619641647827_0.45462855898444654"},"_hasShrinkwrap":false},"1.8.5-canary.1619708354.0":{"name":"@joist/component","version":"1.8.5-canary.1619708354.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.5-canary.1619708354.0+c7f7de9"},"gitHead":"c7f7de9bf9a182c0cac9bc95a3abcae8a6c2c26f","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.5-canary.1619708354.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-S4P9bd0V1Ho2mWXdjQcqtO4PHpd08tczR6g9EJMHHvb7t5uvtTayDhAoMrznl8hRQpKXvoinmkcTUvmURp7D6g==","shasum":"dfd592001b816484e5e42b162c1ba026ea669aee","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.5-canary.1619708354.0.tgz","fileCount":32,"unpackedSize":56093,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgisnLCRA9TVsSAnZWagAAtykP/10aCJqm4Qo4uD4HGyHt\nlUGDH8UW3ivs9PSviqG2MXrCn22BIE6J7NrKdIL0anHgT4Pf5BvUguac3RiF\nL2FFdjHrf1SKAYFReu10K76EGfy6jrn1LOStlMR71ZvbP+62w2jIahXT2Q96\n3KVadeEn0NyGwi9F4TikCBF1Q8DbEZwR9XzFthixKKkuoMr60DaZl+BGJ/G7\nEpEOtKk6gVm8CQicmoUjIopF+m+9r1zmukK/7gzG+ZYgleSCaoSQCFU9el4O\nbbaA0OY/x/BzawpeI/rpKTJMFESx4NFCTgYKHZEFBMcXHQq95WDkARUvjOHU\n4Tmg7O4IA6023ZkmzVBioM9baAzrIGmuyhFDXKHcLVpU+l5NRW9jaoI3PwzM\nhgH5UuIcDkEU0bagoNBYMMtq+/A5tRAJjQQjazpDd5wpJs5mYvGhpr8LZN3n\n38lEFxTErlYupXn5p9wuOlSEuz8QHfZqbQ3QKLq6nC8nVC4iMAXoMmjvuZul\nY5y5L/DKvWbJEwBm4capsRV4o107fNyIDFEpQYaoq2xf5TyGBxtt7p7afm4n\nWGpOaPDnj7K9VzPDyfRfzFAt7ZAb57EBVQ+6qW+BIyBhtc9iCAz+pequxV6v\nc8LGF4uKqf+sOiDE12iSco1C8E7mbK07IBlXfCiz50CJUh0BsvY6BE1l7s+t\nkPVX\r\n=QA0J\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIE9ZphTkbcvXN7dkgDwkPnCpZe2iysWLhGvz1O8C5C2hAiEAxLaSmf48hZhp7L9JX9MPmYneCbWz43vuyUp4VGHjrP8="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.5-canary.1619708354.0_1619708363223_0.32891854078503946"},"_hasShrinkwrap":false},"1.8.5-canary.1620101283.0":{"name":"@joist/component","version":"1.8.5-canary.1620101283.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.5-canary.1620101283.0+b677568"},"gitHead":"b6775681854e683a0c4dc6ed8965a5de28f97d74","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.5-canary.1620101283.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-8FWFXTfN3V/a6zUSbjuMSC7kfm77J47nUqcDSUpNbVRuBne7MViEVNMjsWC2siOm6WgXP0kdsqmuoYitaTiwzA==","shasum":"442aa200d2fafa9fcd0aba295807a8001b1ed6a3","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.5-canary.1620101283.0.tgz","fileCount":32,"unpackedSize":56103,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgkMiuCRA9TVsSAnZWagAAkmQP/0q9gGz9UUFblagZpcFo\nyUdUvH6wx5Ozdv1f25azZGKE4KIEDUYEF2w3RCyLJNcTfG9ryAVbpmnpAdCe\ng0QWZGsGwhLGyjlSotVRjXuDVQM67jx7kyCSp+8sC9AZTMXvTLpHH1J/rcE9\nrqhSxrirVrNB4pvzDUUmWfdVHGaM9WpYN0dO/FCy4Yb7nTzfLulNKa9jDwKs\nfBYwSLlx+ddwI1Npv1dpqaFrAtWm5XIiNRm8O0r7Q2FFRLR+lPMXzJf5rssj\n62d5okOcezh8Kg5fcr7Sxnz+RBspYCmt8crkmLza/dDUhuGHB0Kfj16i/Pj+\n2hY3YFVaFcgq/S6iIQ4jGnlIvitlneN1dxPJIsExG2lK6Dut5K2BvoKXZ3jp\nJi/ItAxTvI3WnKDv4l4mAbf0MGcwxmiBYTjQaENag/JYNgpHmTRvixRxEpAp\nqGTdRipwmaLSlZM13as6xDUfKia1WKfdBtwMRvQPOWwYwoQS2i4glG3LetPI\n2o0Y9Pmmd+Mn0+FZvbUTE8cLHIl96HyVwEHDXMnZT8lHzo0EsjZrMy/qB85M\n1OflnxdIn4uIxp1Ayb6Ura3XtqFBdvgzxD2MlGsBFs8maCJucFmsfFlBrE8f\ndYlLtu5WdRhdY2fzwoKmx4L5wOwHGwvcBeW8VnoljEd6Q+AvwF16yHclA/5t\nwqdd\r\n=8mM3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDfIsvMK6WDyruwfO4z7NDgxoZoNLpULKWRFotkyXFrfAIgKOIzH868CSoU1OhzybOlHeUmVSZdafWcmcbOvb6P134="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.5-canary.1620101283.0_1620101293978_0.9531269723695783"},"_hasShrinkwrap":false},"1.8.5-canary.1620138949.0":{"name":"@joist/component","version":"1.8.5-canary.1620138949.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.5-canary.1620138949.0+1413f4b"},"gitHead":"1413f4b1c700fc09b0bf060a3ed9c71000be994a","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.5-canary.1620138949.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-qhkeUVdfzDDfBAUOLp0uF1f6V09s3bxhjwjvfw8maw0i6qkXdugVi+4zhZt1EHjEVfMHKIk1HMD+cFBciW4gWA==","shasum":"a6f3d5ce5749a637f1d9b8a1430d36e52c4506c3","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.5-canary.1620138949.0.tgz","fileCount":32,"unpackedSize":56104,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgkVvOCRA9TVsSAnZWagAAEFUP/jqKH2QLseAr+i089m7+\nWDiTuKv9U8VI4WO1EknLXxe5eOIDocMM4XAQ7C1h9LJ1QKcoMU+6hHbSuRdX\nBsI+HaBA06xS+G/J5R1PMOrV6wFUL6/rux7n9gGdyjLLpLRegLR1QKoAB8Cu\nmpiE+QgeMy1DA5MGJqP/pTfSE0l/4H07QkExUq2PemNA2Pt2+8vP+oZ1huGA\nwFapL7SNdnm/vTrVabCPHJGv2tqhmSMcsFi2wV9sntUE0k6lNMXS7smI9hCy\nz1mMSFA7BlJ3cxWk0Vymq1IND0+Aa54SiUQev0Ohpw4PRGBiPgpakLXFxgYX\nDE+H6ZZUc1sInSsI3jBVrAUbh2wCD2wbmCb8PlYlQRzkluYsJ4TX7biN3skk\noZRHB29wPYRSZQbUpCqj5fazAE/jaY1NrFdAyDQXTnqll0pGdk/YLPcIVIwi\n1TTkGoggaZZz/0yHjeTvwhnLSQ8iZXXOy4WVDUbxYxSsiPernt39gXI4XUUY\n9GJ8dKRZ6mtQlcDI5EdGOi4YBaKcik5wVv237UFJlO1tyMulZMxYO1psUlE0\nzLwCOqkkXtkMZnC/0Y9OytQ0o07UUuXcLmnB1OCDz+CDj1i8kNHzVUObh68P\nAoqnjEjTPFz2kDgQ5WmqtnXTGPhaB/42rR+6LZfpDqhzdjQr4JOMFZ+u8xI7\n+CNn\r\n=e5zT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD+AK8JQQupuxjnJw2Cfcix/dBCMLI7MiILxzqnlOy/kgIgBVd0oSn9lFVATRpsG+ubiV8oPSysNlSp/fehz5PSqBk="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.5-canary.1620138949.0_1620138958007_0.381302114463254"},"_hasShrinkwrap":false},"1.8.5":{"name":"@joist/component","version":"1.8.5","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.5"},"gitHead":"f23e1a08941c8f50fb3c708ec9542c78d49e5043","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.5","_nodeVersion":"14.16.0","_npmVersion":"lerna/3.22.1/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-UYuV+TZefyIYdmK4orVdWgRuxeyV/Im/o6JJAK8nQV71MtYu4++8uCq2rjcGH7TkurfgxvjB8WMRpNi538/bZg==","shasum":"499e2b46c7ecacc3a0459d82ee95bbd26a5ee880","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.5.tgz","fileCount":32,"unpackedSize":56048,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgkWPzCRA9TVsSAnZWagAAXaQQAJENV3+iMptEBlt3AXbQ\n1nv0tStF2CBBeEeu07fGG04YiuHn9zHuMKtkvUwh0EU2WTs4/YDUmSxluijG\n0K6e4JQ8Gk3slX+4Dka2+xcUGH12CkfEqZ46mssYkEfZcsAhhyV9pdNX7HhI\n2HBzoXPSaYKYgPHS3N46v18W10jFhD4eSvWoE5Yb35V3EPWY5Sft1pjlTN+P\nP88UuHz6enr/ory4pEXDLO2XWB7ZwPS5AxGn+WjlXpQEK1LlsoDlV94lukjh\nkEVZ0OPL/8vkUBWnSbnO0rWeW2Qkcpmji0eWNZXUg6hAYfNC/9vdnszM8NXK\nll5i9hszpe7o1l4CNjZkb252mJvuVD7xIyJkweQ3FEhWPHtmeApzHqQv9fSu\nnzS4eilUxH5Hy26lsm4FLYMrXe1wuFj1cubWKLOM24s9BxO+3e89QMqkmEc7\nna0vcs75Y4fyaebRpuASim61X8qHRqu9OLQPlAjijQlZf1BMU2cGqnmpU0GI\npVOqVoVO7Wo/SZ2BxSNfgllgOMrSg47gBgZ/3g2v/6idYCz7BMkVJLsD5cDu\naxT639Vs8o89iiDvicXm2vuagJ/PPxTxfTFUnHrjB8tFqd8okNUWkNnMFL0S\ncOoRh2NsvZFcv3tmK5Fm+KVuFF3tBFmR0B4FZ+cgfC/O+/pzyoeGQ1Jk06Ur\nCqlB\r\n=iXbv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFUtcvtunmWApe3adbPSCDAd6ZJn/DSi6g+pm85MVvLuAiAZiKi6ptyA3pQXs/EpVBOeWkKtJ7N9AVVGL8NmzDefUQ=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.5_1620141042588_0.3485808375279267"},"_hasShrinkwrap":false},"1.8.6-canary.1620141152.0":{"name":"@joist/component","version":"1.8.6-canary.1620141152.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.6-canary.1620141152.0+f23e1a0"},"gitHead":"f23e1a08941c8f50fb3c708ec9542c78d49e5043","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.6-canary.1620141152.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-hkrpVxP8l4tmbiBklyfkJpVzbCsdxyqd1WvMv49LLWG6lpXxhjEW5T/IxRTejHkzRdi0d78AKu0hvhrpL2xhBg==","shasum":"3ea7c229580f0d72fbc89228c0ee26e772aa82a8","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.6-canary.1620141152.0.tgz","fileCount":32,"unpackedSize":56104,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgkWRrCRA9TVsSAnZWagAAKgIP/jVyIWOPVLXfJiq6XbUg\niqylr0cYqaxTJqjUYCHUkqAgGcEb7CbrFHmUxxsbq9VZ32UR8Q1XIt0+JoqM\n5Jy8Ml2e2Zapgybz27j4zYsZIvsfz/o7y2wmFB/tZ013hD5eKNERgoK4sofD\nxEBEbFhxZxHWMv/tGZFJkpkN3V9tTOVUDLFfsIB2JgNUt3CZcvlyMUA9EEUZ\nb6WBtxDEPS3JbzN/T7CAFrtR+Qtn4NWSO2exTWjXLc+01P29JVXDGVtUE8r9\nqNJqzEQFdyhFLllhyjlofJeFkQYUTY/Z6W5g6oIohtITc3HXO3JXhqCx9CU9\ntv7Oq8vcJmn9xyDRGUmGUrWdCDojno++fqOiqjpdK0LO98L2D9rlha53sKsB\nwE41dELylLP15i78NvjPb8ZdBzrSgungfbLIuFWsDnl+u6/deM1a02m3Nbwu\n+sbCEGsiK9TndjtZjY9Q6ZWEwyt1ej0tTGP+0VdBLAFUA7uie4DAf14dLMei\nDAVNlJY8yJwLqJkVb1p++byKHMlXcRdydQta6J2K6lAn8dN1Kpf4lMk/cqTl\nzSX2V9zSoLFpUnH6FdW3AoXK4aIwIHXD2RYUjfuevAKt7+03vB1fBTfsaWj+\nNfppyF0ujNA24U9ypCv2TBFDScO73BjbzrXoBP+f4SoAdksg704yycZaU0gw\nVzZj\r\n=VtcT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGURF+71eeVy1d31BcTxXno+4YQyoMHtVp2wKskHBhicAiAo8xLS7oibID0v7aJgWDBAZn/V9nGwQILZp/4xZecS2w=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.6-canary.1620141152.0_1620141162603_0.4345200885002376"},"_hasShrinkwrap":false},"1.8.6-canary.1621387626.0":{"name":"@joist/component","version":"1.8.6-canary.1621387626.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.6-canary.1621387626.0+20eddc1"},"gitHead":"20eddc10ae24fe3fc2d8c3a52c4e4ac2c6965ddd","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.6-canary.1621387626.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-kgS6Npk7QbN6NlgMh0gKPiyTA4kUf2pIHn+1/bk0sbZkHKO1q4OsqA8O0bbEe3+lm6cwqCa5GsO7FEPm4g5sMQ==","shasum":"137de687e1f52deab89125f82dd93e46180e1c15","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.6-canary.1621387626.0.tgz","fileCount":32,"unpackedSize":56307,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgpGl3CRA9TVsSAnZWagAApxcP/jm5LrHXeHxe0Sq1grD+\nU82Qxws6tipVSqIGaO0GEOXWgMXG1Jtj3mDFWl5ncYx8z9MLvd9dn22mCJLX\nG8tDzu84/Fs3jtWwVgaTJj76ek6EZ2SAeVP6O8HDkrSiC89nnLdzi3VYldN/\nXp8nd6fTvv6gS7Euuj5GRDj1sGgDsGNLMkYB282Fy6TjAgKSGJcDqk4Tl6J1\n1xV/ccTrRAwtb9WhnAPQNMrxjqvE4XS4BD8fI6r4q/GU7S3REQUB1DN3Goj7\nlizBAY/9PkrkEwzEHnlwL/JeNUYfH0EC1JNFe9fMmrr1Pi7uPtJioc0/9Sk1\nBbw1h3i8UOitfjbn2cd2TPo3O38WO8ESTicKE/t0GaicDw35lBwFyiLUhO5V\nuHQcNLnnSsrY6wB5SJF9HgCIuICwz11Ts4v46spkpuqDm40InmypMob+YBvv\nC+WerN2Vvf6RFVqgde/nw7xj67iBYwsJqaSnoYna55S4reGKuwYBOVGxOZk/\nlW2oZ566Yun8YF3YwJUHA6zRFL+qHB/3AyN1utAZWXm82f+gFZ1gnMK5C2P1\ntCj54EelPLLV3BmY+dsTF+fPPHoosEJwOgGv5Z0lpl/czkHl/rInBgwVL8w8\nYoWAtkI5rgKKEM9WarT1vnxF1BdS1DTyqc73Ofkyi9Xsg5RQrqZ0NOucHXPs\nDXOP\r\n=ZlNG\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCpXFBftEUGLXVQO5MwClB3toMD1rCnT7vxghgfU2GhZwIgOfW9UeqKaOqb5M6JSAbvYfTRy4xXhdjKeEvXYvdLU8A="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.6-canary.1621387626.0_1621387638377_0.5307537460592804"},"_hasShrinkwrap":false},"1.8.6":{"name":"@joist/component","version":"1.8.6","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.6"},"gitHead":"bdfbee1b08685b34011dc2987f57dd60b6ea64b0","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.6","_nodeVersion":"14.16.0","_npmVersion":"lerna/3.22.1/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-DhvBEoxS8tNE7C28AhWRzNPSkpCLJcE2zUdw+tmXld/W67KjpODsAcubyeWt7gTpP0hX7hZ3RJspUOQFAwFjZw==","shasum":"97df91fa3a160407002be403ada1d3bb5c4e8f54","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.6.tgz","fileCount":32,"unpackedSize":56251,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgpGmiCRA9TVsSAnZWagAAEsMQAIPURGeeSwDwgwxLVJ6P\n6LbMDNCEd60P/cTCGFCztTYf5E3cuaRG1LZuNOuDsVW+yyAMQx+5m1JCsmQ5\nP+jBgIHcDGMN+s9MoCiMmkf6ucmC9jZoOCE7+PdyvgTUpttfeYYIvHlTxJq6\n8gwqxnsnWCqXxfX9qsIg5N5g7+BK3EqHw31OYqXvswQrbIczCk7lsnQl+LHA\n2NIb1wUssQQJBsY0ucNFNriimRFDl2AbARqDKOtbdb4Ie1FVEHOM1njlHcff\nd/bgnAiA1wbophyQ0nRYoC6S47uoPMhnSwgAOOiXl73Ro4lFLU1vLfMEL9F2\nz1Pn3Eez5OgHt2dtBgEZv/Hw2GVjUp63Zw00/wol588xR0tdHvoG79vzXUvQ\naJnUaRYv3EMGCfiiqj4MoT15u+XATaFfC7xOJyr9QqAUbE6AAjWPhvTBbuvg\nmKqkx9shj5JA4jthJUc7fouo2YHJM7wYQl5FJguWupzSBMq09S9aNKAkxROi\n8UqPwjyEA0isIT1bBeW/If3bCnnRxFQFYr91ugpppJ82E0c0g+xmmh/6vmiY\nTDpj2TrY1BIvErbJ+Qr88kLJzVoe0ttHanBGVaSDGtTc9goQQbos3goEAWTW\nqXepEwc3PujAym1BDrAMwGNiNRo2c4ot7jR4UYSkx4fYZONK1meCAByppJ+P\n+j8W\r\n=xz+X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDIiW0kcl5/sJHB9eOxY+b3HHA+OWVEh1G3eEzIAGSiqAiAHwtsStp2Ze3iVWmTNtPR876iiSxkFMBA9lWucavjPzA=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.6_1621387681855_0.9080856607062722"},"_hasShrinkwrap":false},"1.8.7-canary.1621387788.0":{"name":"@joist/component","version":"1.8.7-canary.1621387788.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.7-canary.1621387788.0+bdfbee1"},"gitHead":"bdfbee1b08685b34011dc2987f57dd60b6ea64b0","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.7-canary.1621387788.0","_nodeVersion":"14.16.1","_npmVersion":"lerna/3.22.1/node@v14.16.1+x64 (linux)","dist":{"integrity":"sha512-SoXRTzQEz+ec2vGf3V/MGDT3l7o07vbQQzeD1RbcU0lX57tZKykH013mHiXW7t8GT4Ikfqa1t7BNpiRlFF3agg==","shasum":"476ca035a8c7ee7c0c48975ec652efa3b185b52c","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.7-canary.1621387788.0.tgz","fileCount":32,"unpackedSize":56307,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgpGoXCRA9TVsSAnZWagAAxGYQAIPYKurtWAqsZNEG6dOS\nIu5P77QWHXn615f/x8/mPscaFLAxoar83IjTO5u+JXezQKdOHf9Yc/GKEZpE\nggnZ/jVspvNBAu9aVhY1mf8uMx5zzwGznbA3seZCTBRPhqiS56f3oX5eaWkC\nmroNNAhDdZbQqAMrQ8X+8Uds+M4hnLKSA0dcqXvfq32iyUa70zSoB6bl5PvL\nqGtQ+khPWicuIc2yBBSBt/YfzBqpE35hz0ulEDLUs/fRzJixSsdmkpCoX+Vj\nEUhmqr7jscukERwVdjbrpn6gA8HTJRCNyps6Outci0FqLJ6oz0A6WvGtIB+T\n++C/bNuKn6mVSTUCNKyHUCY/bAOmorIAdH7gHPZwC7upsBNoh+0aVlz/latt\n9IaQKzA+4IZnJFH7CErNFuCkr85uUJy7J3Gm7uB1hr5XOc78MftLxRVWA2ts\nn93YPozYK1XB4vNk+iSdI2XrDAteDbCZRu4MP2KptDZ/P7LcK4JysHdkwG39\nzeYc/7UUmqmzQDtW+Isv1k3zepXfDvzrvcuyL5QBo/ri3/fp3BRD8plUVKed\nt+EsHs5/b3lB/9RUKNivBXGD9466kQz2qx0MX7M9+XAXhGW9R8pllAxoYtcg\nt9GdkkxD9oWqp2mBA/LIm3VydIncVe2ogSYhIv7D+LzV+wvdOHI7KstF62iA\noqzX\r\n=raGq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCEhrjF60bRcIF0c2PQjS1WzUp2APM96AVoxPXZyq8PnAIgYaFZznYTUkvsSnf6vzzvvkrOvGA0V4D/ue/aJ0JTfr4="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.7-canary.1621387788.0_1621387798783_0.8636709434533034"},"_hasShrinkwrap":false},"1.8.7-canary.1622044874.0":{"name":"@joist/component","version":"1.8.7-canary.1622044874.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.7-canary.1622044874.0+52ea0e5"},"gitHead":"52ea0e5764625d69423af714dfa3499fa1ff3491","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.7-canary.1622044874.0","_nodeVersion":"14.17.0","_npmVersion":"lerna/3.22.1/node@v14.17.0+x64 (linux)","dist":{"integrity":"sha512-Kpv99T+qtjkord25tKRVPrVfee6gEz47mFdmKu/Y1Vb+XWZnLeUqqHCfv8sKe9evzYM+/4vkmBg3XqTZ+LiUZQ==","shasum":"744fccc386363009e4df4a341a1800e338eaf760","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.7-canary.1622044874.0.tgz","fileCount":32,"unpackedSize":56307,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgrnDVCRA9TVsSAnZWagAARVoP/2ujAa2yMwJzO3MJ917x\nKG/9W1UDCfFdURvh9dDCnV5m/wJeVEiaLKvk4MxahXLz5oGe5MSzqSV9zxmx\ni4M3pjpxc9qVDePRqKKQQzcxUrfOqHCQYdpNUirdhtA5A3OshYAeDj39rwJC\nXsNFTJVCre4I4KTzZFIJWZLeiedf2GPVEXOhu6CXjZlb5N8BXX24KBTV+kah\nuTIlCxYAJBvKyUUUrrVxNqDqIOpKbvADunzaHSNXBX2kojOU9QCoKFPM1Nav\nyULbSFLY9sRrivi5S5gGLWWM3c4Vw8yaSIJSUBCvLgW0AUdMOs2XCPBzrlpR\nVUdiAukc53rC0Yk4XE3d6EvTQRANzZg6UU373FC86MrTbK5HnSy6VvpwNb+H\n5texXcdO51fHgR49GcGh5MmNg70f3mUIS2x3FZNuaxO8INAOnbA+W/mYjb/g\nxv1J+oPSw+2BsSF6q6Am8ZBuWbnucjE5t0gf71/ebFX2HQfJRmzl9s7xDurV\n6EhaNVe3lAOFk3/JjMS2rjk8tWAuiavymlltmfCFXoT9u2w6hYxHSmZ0zLCs\nQW3DB7YjqjZdITtQ034dLVsDNUQTqZqpZVVmVJbwU11pPi2PLVF+Oeq9Vi5T\nyAXPKZZk1dYxoIcN2yfg6fyHtSxnAXZUS/Gyd7CHlkqqudU/xMRmgdajCfLa\nCR+K\r\n=+Njk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICqV81AovdSYNdsr45E/uq+PoA1VUFxgphCmwiwiiTpyAiEAgpDKJsqzm35p27banyeChTzf9EK0dNgtutTfsE+/dQ4="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.7-canary.1622044874.0_1622044884640_0.5602956433919437"},"_hasShrinkwrap":false},"1.8.7-canary.1622817902.0":{"name":"@joist/component","version":"1.8.7-canary.1622817902.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"prepare":"npm run build","test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.7-canary.1622817902.0+1c692df"},"gitHead":"1c692df3af65eea1619a356db17703c7e4729ce1","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.7-canary.1622817902.0","_nodeVersion":"14.17.0","_npmVersion":"lerna/3.22.1/node@v14.17.0+x64 (linux)","dist":{"integrity":"sha512-C8fE+Uh1ETblliY35n7h0ZnvylLgQ9y7YiTOYZkofZ0aSYHBNNv6iLr7iNBTFACgVlvchektsxgkb5JbqH+F+w==","shasum":"0068191ba9df407f07f3b6a8e1377c09513c0e64","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.7-canary.1622817902.0.tgz","fileCount":32,"unpackedSize":56307,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgujx4CRA9TVsSAnZWagAA8kQP/3od4NLci8G5kzj2yBCQ\n2UbefLKpYkDeJyI02OZmJBiqZjxpoIkec2LSGSdhD1w/UvWngYQ8SzPMskO2\npZbi7VDNyPxkZiFFDi76re9/HBuRg3YwDvQKZdo0kUCtEGufwBD+TsJp/8kC\n1y/hoDDIMQketNNK1d8UFecKcCe+xS7WhX/3/lqT6ez9lvYgAyHN0Cx571+O\nErd5nU2Acq5pbOFv6nSpwe0WQRoj2Nm7kpLglahifw54BY7LE28KYp77xZdH\nTyqnH0XuhhWSh9fGombSZcr3H6HcHVeqD75UbZg6e60HMA8Dd2HfmVYDUZS0\ngVDRjc7E9FG5yPZvJzrn0/1VS70NH+fInavl+JjqmoxVE9zj7eIXv6A18wUL\nukxSkRluOoIeX9FpAWvOIJXGsKfk7OQe7y5Y/QA7Z4D+LLuvP+hLdLkmQvxg\ncyfZIJ53ralO4f9wJCO2lVm1kqguBizB/YtXnJvTM/2sTUgtKes2es/q8frr\n6Uh9sDXtDLmcDECtMcpUVG3pvb9572U2kDGffzv39yDSvlgsR8Fd7DbC0ALF\n4hY7EeVHcqRKUUIZQEnJxfkrCgTIowBbseYHMzDX2tcTQJu5pE7DyjPvKVWw\nplhUScODQlUWgUk+8JZddLSovuN8O01Ea1Wom/XugI0A/6Tgbc9+5dAe4ow/\nfaAb\r\n=q65e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIAPkn8+HvZXYsQJNrzk+VkkRRzBJLYVqyn0OqTNXLVl8AiB+hvgJ3McD3ICAWeKLux11DYq82a/69im2H7RkuGjHLg=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.7-canary.1622817902.0_1622817912300_0.024005170901305162"},"_hasShrinkwrap":false},"1.8.7-canary.1626922834.0":{"name":"@joist/component","version":"1.8.7-canary.1626922834.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.7-canary.1626922834.0+147229f"},"gitHead":"147229f8dacaf1e650a3bb1d825fc88c7ecda661","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.7-canary.1626922834.0","_nodeVersion":"14.17.3","_npmVersion":"lerna/3.22.1/node@v14.17.3+x64 (linux)","dist":{"integrity":"sha512-sKiAFrGpoTEdZygho1WuDOJKryfqSl7v0aD2VTdDePM+ICNk3pHHGrYhoNMmqXYhmYmrAnsrYEDL7jcGbH1Wmw==","shasum":"438238afac4dfda86e9209ed75520e89932fdb39","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.7-canary.1626922834.0.tgz","fileCount":32,"unpackedSize":56275,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg+N9UCRA9TVsSAnZWagAAYlMP/0Rx7+L97BEmO2RJ3+/m\nWlKptkqKdi3eVf+leHiG+zNB5kAZL35bN64R5UQYnSIs04lfU4SBCtDxAMOK\n0fG96JZu8aw0OlMzeWFCo92Rv1A28Vtm4OTkVD58iCS6yfzwKmyKnx3hcybZ\nOChdDMyr9pNylTHBEwgl+eDIVFD9QoEEbQ931Pr7090q2W7UpT4xNUd99/4F\ny5pXCiwFUEeVNJdb6OxAEKdbdxHW1RQiFMlhuiJeqahKheSbomD5cZmZS3Wl\n2TC64t/DZUEYdKLBnHZnlJkAt8c4dys2HWhk9V19u+0AtpweELWKtuPQsGVe\n+7QXUnrBhkep2u+K255twafVec6xPZNqFUyf/BLX4LZwyv6OftXVo+iFiej4\nsAn8BWBDpDaraEGXGh9v68rmRziIW1qqWFiAu5c6qgKEMs8fhbqUbe13+Fj7\nbxR/0u6P5esESNk+Lw8A+axYryVANCcIP+VDwgSX6zJJ3aJ3GMXYOYzrnrSr\n99Wg3+zC1KWq9e3M/Ot+1o2xFNl7wZ3NlG53p6NlZEnDz/zVJfg8Jl7niddy\nd6gdGF05Cyo3B74shvg5lmk7cq5lVcEZqzxYldniEFT5DNR2Sf8kGzY0rla2\nnxc4xrVgQv0dHj2OKeLY6C8YRQYmqv+rh5ljXNOzMrqYPXIiJWHlEh4CMUTJ\nYo2E\r\n=dI35\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDxw/yCLP3hD189U1mpglV4fqr9BBS/sgxh/4nfITzEaAIhAIi7iLFhRcOGighgSjoaCepCIFSZst7HC+abI8/r9zIp"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.7-canary.1626922834.0_1626922836714_0.2533259904490537"},"_hasShrinkwrap":false},"1.8.7-canary.1626923316.0":{"name":"@joist/component","version":"1.8.7-canary.1626923316.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.7-canary.1626923316.0+56a0a89"},"gitHead":"56a0a89d71a244fdce1724c1b00b1065a39554bc","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.7-canary.1626923316.0","_nodeVersion":"14.17.3","_npmVersion":"lerna/3.22.1/node@v14.17.3+x64 (linux)","dist":{"integrity":"sha512-QAWnCp7JktAy0SfF93s4GKC8WlJHHMTq94LAocwcb5Ymbzb86o4B0CBdue76EcDgNrxMt8XjzJMXakAkjYoowA==","shasum":"7ee55f4a0f5bd11d614f5e10775fc7492ecedbd1","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.7-canary.1626923316.0.tgz","fileCount":32,"unpackedSize":56275,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg+OE2CRA9TVsSAnZWagAAWQUP/jA+ei11FYIukM3QSn9B\nCwkHArOj+tEU/hwm0X6aQFLNPArJrgVFo01Trw43mPmKcBfBMnakL22AStxg\no+azvxeFzm2WF2Rsawp2X06WlJ6zcgexcrTUyyfb/DTQ4wUjwi3WbKbNVhqS\nTywSvObJNmbu6kzNf70S1egqXp8gJIAQo+02+yjl0tdHC0/AXvkSMoqIdUMo\nafcd2/qDO1F+Y/vhDgPLO2acSkn4JhI8I6aAeX9SrfKa2EHRj8PVA07LzhCe\n3RW33TVPS4yY208KPxm4zl/WqYkwXFtihAoH6B93ruJPqx3BdJ+DMHLgTy/o\nzQR2NBgW5wT4/6xeCVa6VrltjQKBN8c6goSWDi9lzkfcsxMRqSpzzWS+DT3g\nalJ7tSmVICbH2Q1IRzi41OKTCXlDJZxTRRXoAR2nbaHGbXvw20lXOqhurCR4\nYvO2KiV/ipnoWoirMkrfu43RTBvqEjzSlb7oSCEEpjMLW28mE9uRZRnadAeE\nKHXdf/kZFfm9W391Oqeb7vYJl71gAVgvQ9bFPTByf0xKlZibFB1B/6nemEVx\nbaLFU9s0l4DnmHzIOz8JC7Pma1EoZw0rAvlbg0UKQFk1w5SiGrtYgRf1T+UV\nytMRc0Lqqf9w78D6uWSI5SMWkT52Lh28+J68t2aDGbXJ4Ydn4E2Ojej/n1rV\nzDJ/\r\n=FTPO\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHaDVBi9gtv+MtZTbAMAYBmx0zfEvEdTJf295+lOT/wZAiEA6IeqZsdUCmqY8h5N3yyO0XFTzYL9zNlDKyFNGGXc4Pg="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.7-canary.1626923316.0_1626923318254_0.6168782337349068"},"_hasShrinkwrap":false},"1.8.7-canary.1627917432.0":{"name":"@joist/component","version":"1.8.7-canary.1627917432.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.7-canary.1627917432.0+cdea648"},"gitHead":"cdea648cfb71802874719d3ee2ca09425f1dc4cd","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.7-canary.1627917432.0","_nodeVersion":"14.17.3","_npmVersion":"lerna/3.22.1/node@v14.17.3+x64 (linux)","dist":{"integrity":"sha512-kipDId23jSb3GWAXQp3k3mfUiiHVtWrWFDZfgmC72FAWVRIGah39nyExQyazPp4KXDDGDQTn8cV2lNbe7yjJ9w==","shasum":"49fd9faf74bfd0759281d144b11003e2cb8cabcb","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.7-canary.1627917432.0.tgz","fileCount":32,"unpackedSize":56275,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhCAx6CRA9TVsSAnZWagAAfIQQAJE75nD13gNZN6g7O1Av\nAq1rU1z2JLp3fUtXCaaVMvMzYqU2l+XjN/xU2vBLICdFLCEr8snJTQttoiLC\n657P8Lwj3e6euoG+pVkRXUVGqOuDrIv6q2bM44Uxkc3zuwQlCmYmGEFl33ww\nb8K9sSu32Ps8eUGzmnSdZrI8gvLrV++VDXq4ZmQ1eLqCyQm/K3UNig1NqU7h\nKvOsVdUU83HNTqvBkTbHy9TjZ3/dCP5MNuLtf69AWMNbNpC0L/K7IRvzMpV7\nVcZm9lDFaY6Dc+dGxgepUg9fWGzIDqEvrebmv1kG9xixpoNWl6XxXnFdUQk/\naMrcQX2ixHB9+OQjPU5cQZy6qec3l1fzXqmnCbZmAl/zWYKxUEUkOirBCLtW\nvzggXeOa0ZLTFJl39eqidh0Gcp1002mMezdzr8traEK5VqOiPNJgwJYAvizz\nDomGAqjSEOFTgW+LDUir+cJhWF3PH8rgn6XA9gbSYjPP2B37HVAmIEuyxzNl\nZ/q/uhNvxLXmqspoHNwLi1Vun0jqhasuu9VG3EjlT5HI98uLhfojq+BtDeXA\nGLRO5NRcqwOKjfCggk5PlRWeERSLfAxAa1/u6DRUKG1RJTTyfYfUuK9XtwxY\nKL0DvIWxBKe3DKcP3CNRJqSW2eG5m/dlFQQkTvW0cnFN9hRSZAOL9VyXTMSf\ngW/S\r\n=j6eR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCQ6iy4/Uk1a/ibAwPUznbrtcOY0PN6UQMNwI4Jaib+RwIhAKfzDqhhBtVhmOdFMP+Bgmu2d+RSA831JWu0w3yuVEiA"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.7-canary.1627917432.0_1627917434368_0.3923306539344127"},"_hasShrinkwrap":false},"1.8.7-canary.1630520794.0":{"name":"@joist/component","version":"1.8.7-canary.1630520794.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.7-canary.1630520794.0+81e9671"},"gitHead":"81e9671b72d64d6a782d7217a9a9d07fbd9e330e","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.7-canary.1630520794.0","_nodeVersion":"14.17.5","_npmVersion":"lerna/4.0.0/node@v14.17.5+x64 (linux)","dist":{"integrity":"sha512-5t6Klx9hZtJ0wwCFm8wJ/kSpwSoaY8VfABXM1mbNDKk5hWnlqLWXg9AoOnsU+DKt3Xv9sRR9ukeLSvh2HsIOfA==","shasum":"fa28c6dd4f09de0747966765f5f48ae1cc9287e9","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.7-canary.1630520794.0.tgz","fileCount":32,"unpackedSize":57654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhL8XdCRA9TVsSAnZWagAAcFoP/j6R/9hG9Rdh/8459WWc\nyK/4bnW63kaoVffJbrqnOy39zZKp9qO4tN2Yg2rWa20JvsHhSG+DSmonP6kM\npAr5thO+gNDoWbIie2zUDTvyOZMOjbi2KsqNB6CW9c7T2O1LAEs4tfk8wIBg\nsSrx8xntM3GxWJqhx0Tb9oGD2ZF3ZK7Qz3Z45nDMU4BJMOrIWbtD2eNVHiJv\n0IFw9HsM44W61DfhH5gyJXWyW4B7Zn9wBpzWUt6l4p52dVM71LdX+/ivo0rr\n3HJykA0aRoWBfxdFKMLazIJjqRbzxBdTIAbWROPhS6T3tR35qHzb0jpU7uAu\nRWKibbfbPW4paNgGD8FVhy5h1CZgVgBZk5mLEuJUapKLvj5voGCzmFVAbIQz\nODV7YGEdV/eZQarmu7PXShvcbZK/LUmm3T72KcD35Em84o75RvVQKWP8JjBy\nyGcW+QmoYVckKws+NTEJWsOmELrZOkKpDegLCrDYYgA5HoFcAkyI9puHNraX\nGBJ+KpMsU8TBIA3Jh5uSR+pS+93PnugIiHGwNA+JjatbJJFaVaTwm18mmfc6\nIMILO0ZVJmd16AEiPu/ode6gypIFj8gMQi6BgzCAnvJ36ktCahXfsAtQjBoM\n5/EpxK34BDpbDOdyC9WQ/tnjfshtHIUiOD2GykcV36TUL0qadf9XkTNBP408\nmROb\r\n=bqSk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDk8OKhnNmMhgAD2Imk399EeY76eO1D5jdVLn3U1UEE7AiAxS/ZZRuzDnm7IQ1WFsY5Uv0C7MlVu8ETKIG+uEoNlpA=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.7-canary.1630520794.0_1630520797042_0.9311677841452823"},"_hasShrinkwrap":false},"1.8.7":{"name":"@joist/component","version":"1.8.7","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.7"},"gitHead":"7b48f320c338da6e0fbc50b1739ec939724e8863","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.7","_nodeVersion":"14.16.0","_npmVersion":"lerna/4.0.0/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-kTjCyslx6tNJrCYfmWppUgweQuo6fFgkfw3CpHW3y0HKwQ8g/Kxo7yjVJK2F/3nuscXONnuyaR9hGrOUumDlHg==","shasum":"7148bd23ffa8bf57f26c7f8d69f73cb579f0c6d5","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.7.tgz","fileCount":32,"unpackedSize":57598,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCzGtf9ofzJZVkfMnZKEP3EQyRsbaQw4jc3V3/x5SHbagIhAOx2Y1FQ84wQDTUtaRAOtxVYBlQYF28LjmOzZtGRJFfc"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.7_1635519323504_0.1372457013221169"},"_hasShrinkwrap":false},"1.8.8":{"name":"@joist/component","version":"1.8.8","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.8"},"gitHead":"6e51aa13c4c715d7f81494ec7e42ac8196937ce6","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.8","_nodeVersion":"14.16.0","_npmVersion":"lerna/4.0.0/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-IX/w4nyoN0Bb9r3LfP3lzw7M6+h99bJhtjQgLnlaC345Gs8iJg9ms6iJhzK0bRCvCifT3cEXQ9SX1D6uMU7PxQ==","shasum":"391bae206e9d1cb8cdd8eb044e105c4a1245e7c7","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.8.tgz","fileCount":32,"unpackedSize":57598,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCc+jAeHJdcVLXgJOZOLT675fqgT8pYUFRc+k756/f4uwIhAOltc1ydb7kAKPvENM6Y/31g3DoICQt+G50CiOAdkvDi"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.8_1635519650611_0.7686906250303764"},"_hasShrinkwrap":false},"1.8.9-canary.1637250860.0":{"name":"@joist/component","version":"1.8.9-canary.1637250860.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.9-canary.1637250860.0+94cfd04"},"gitHead":"94cfd04e1015aacbc64e197c133d73c190e3ec19","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.9-canary.1637250860.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-yLGwcn62ojfdOezj3eMkDEiCJpeff/WOzJQXW3bpntJc5TkutwiyXtrWJ9H186Fur3trq2LBMDwzu/FYVIzVkA==","shasum":"1233f7e6db46226e68b15701304d776ddcbdd510","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.9-canary.1637250860.0.tgz","fileCount":32,"unpackedSize":57654,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhlncvCRA9TVsSAnZWagAAoocQAJAZIonuBFK2JtaYPqI2\n5jZ74kNL+h9OaCsFH/0gm7WcF41ZfuoE2+viq6E52zUdr5QSBzIrgZ5cJct+\nrqpO3HS3SWETR7iIuMVtU63teQudM/eujfKOBJmmbQndeclg/Fm53DC18VBS\nB+y8ar0w+AgqyDQs8KEYwcLSNEI438pE4/tX6BKPmQQuRARU4hEXNOGV8Snq\naYVzkb2CsR9bVBvPbMDxy1WuncvTv913APGCPfIGNbnfB+rMUXfj4jNxyZHu\nbYvOPP6wMRBgmr3GgZU9H7b6ZzWQENT5IMxLf+2p6yc5SKvjOMXgrviQ94Tb\niPJVYDn5miM5C/QMSo9SeuXCT6QEXA30NZS2CnWu1xVlTMp6S0gtcMgQ1g5f\n2Nl0tYs9tQ4669J4JEtdKDenJ0WdLQ9l7L4DpXuXf7LWC4chvVoKlzrhcVbc\nsMug0t1zA7Qv0s7AY2Pdy9M74i9Fk96mMdexzED8WdlHhL1jqr09L+npZqO9\n0f/PgmQYiFKPCI5h1+jVbhi74Jm9g/ZR3HQtqsB+jhT9e2MT6LTmJMzSUNcW\nThcfX+IO0NtMv63osdc4/5nm2K2Qw2GYa5u5wuPqjr2Wumw/xbeTRqFsOriq\nnSleQlRisTs9xzg0cBSe1d9NbpyorECSA+FLYCtL4WC8sR7cZljkLl+D4njf\nDyN5\r\n=n4di\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBArH1hiypGUurxr1tdiaG04v9KuKbOqHtnlU6ghdc38AiEA/Yq0nGHQIrrIKXwWbYrysPBRoB5uAWHn0yQbcPKUxFQ="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.9-canary.1637250860.0_1637250863398_0.19509922954412362"},"_hasShrinkwrap":false},"1.8.9":{"name":"@joist/component","version":"1.8.9","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.9"},"gitHead":"66a5dd15b5c29530fb9bbd45362e7d4dfe514ee3","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.9","_nodeVersion":"14.16.0","_npmVersion":"lerna/4.0.0/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-yqcGFTu2yF4FnoEXjoJHjAFnu+fqsn7Kd1z3lPcdj3tf8fDAv3KA1lLoAPF6tz/8a6rzN15qjJnj1W18N4W39A==","shasum":"c0eb8ca30c3fba9b7fc81f6d789157fb122e0706","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.9.tgz","fileCount":32,"unpackedSize":57598,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhlneCCRA9TVsSAnZWagAAvF4QAJm3XDUXweCq+9uZ9+rS\nxJRQgkEgJUmn5/zXr2WVpuhHJyK3d1v4nwqpdEYX8dvv9DmuezGjT2VrW5K6\nsuOZM+YSj+gDPhvZ8tFZo84jzsFumqKyvo0MrXf7fDqwMwTyI5ccuBiVRlw6\n1cqcMNCHEwjhD7PwVXwdV1e55tK03Yis8+BMNF0Uv2VW/P/JMXfgBGmb5NUH\na5OfSctPB1t479zI3Gx6obapprBlErCAQk/AcHTsBhSYisWH1jh94q3C2hC5\ntLYY3EAcpcNj0puGoYAI6iJ/fmL4nkOqQXKXIfAccMMdDdHmnzesdWs7KNYx\nDhkpV6uYSR60ooWlrmI/NChHi8NYU+4cCCzSNUuY5JXRQphMko72/a3OjJND\np/VJ9dsAKczfH3UKZ2PDn+G3eUpC9kEi3nnO5DJozTU6dXS/Iu8NxL39LrpW\nnTWGumsk1WOT5kAu7/xWQmwN8c5YpyeFvaRGddM8KmfuyYO3qbYmD0YcMeQu\nwB4VEk/nJr1vvRdUelxFRu/mPAV5ozwjKtL4u1YooPctOSiF0tVUQn+BE/zK\n3WGL+P3Zx4Ub3DhqnFWJBWgyXk7VD1xXuTOseVbiqlyh8r1n/YoQLuSHk+cB\nf/tSOI+PzGi0gY/fyEgUG34vyy1KWgHzu06sGW+uSU8maWhLL+O8k3uxGNVE\n4HJJ\r\n=AI6p\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCICBCJ9H8JsjlxV+Y6536FEo3IsJ2c5nG81L2klYyHCo/AiAK6eU8VZIJLwhrrpXjDyR05sMjKubltUCZvN8NDHU48g=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.9_1637250946683_0.422817349314379"},"_hasShrinkwrap":false},"1.8.10":{"name":"@joist/component","version":"1.8.10","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.10"},"gitHead":"7c562502b4a5ad481f66eff5b8c28855d8e77735","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.10","_nodeVersion":"14.16.0","_npmVersion":"lerna/4.0.0/node@v14.16.0+x64 (darwin)","dist":{"integrity":"sha512-hvilHW8aAMgfZIPf4XiCBMC6ZwXbnB8vtSW8eQCI1Mnb1UUmjFCYiiIH4K6sIQ5wP1prATS3r30sD56jtAGCew==","shasum":"b72614e038f8b82f40e5450bc411d87fa378c609","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.10.tgz","fileCount":32,"unpackedSize":57600,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhlnefCRA9TVsSAnZWagAA/rAP/3eobdmrhVCb9tT64V/j\nBjIz/1ZKEW/dxFS5f8pnQXX1Orq+/uTTEGZTbbm7Wzcb+rRKx1kZtLsOW64s\nZ5G4kzBNsQo1KX39ya+pLdK2BAfacGGSLlZT3O+qM1nUjw3afu43IimLTVr+\nWrfBFSBaf/BwoZcY61j3Sw4Ep/UaURVKmGSyHNpokKXmfIlsJOpugO+SIuDl\n3VdXhUnyd8MqEsEL+gu7FWdkKjjxY22jvFX1T1W6RIVXchxCSXjxX3LK2R+i\n4xZ49iiHu3//XdfmsCjlxqVryzyItODG9bLkk4Nivr1P8KrnkwTXbVubSKOV\noCiEI5ezKwieMTAtJyDaUp0qb5W1YZEiFER3hsMOP75Ka2z6phfL41at/orF\nLurROM1lYDOpN/iHGwxr1lGJtL7N4XlFgW7BgM9tpJtMykqkX63MCxJIDiwS\nXGzkJ+/hnGaVUK34+yCVqnlsD5DItjmXd9sgLUjMbe6m7PUdKPbffv0aFgU0\nbzqbRwkw33MAwQ8XBiPAsFs6XVQcsEYgHpiNSj49CtuDZVGQN9xuNdLjwkwq\nKB7yGbYtOwdPh+SbCWBNETUI6lQoOT+47/YhpNze0tihh2e2spG2nV1pF2US\n9vEwQ9FEBqF6sXJf/1smydh4eNcQ0ZLlqNWonUmXCBUAMPB1M7OihltmaSKG\nQNz4\r\n=AGk9\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC15pVJBHMhWz02n+TDbrkotGSniwsoZ4rh3BvC3thP2wIgUYcUhtStlYkydgn9ecBGsBAtwrj3+c/K1Z1Dr0RDRAo="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.10_1637250975079_0.08093953533472353"},"_hasShrinkwrap":false},"1.8.11-canary.1637251084.0":{"name":"@joist/component","version":"1.8.11-canary.1637251084.0","main":"target/main.js","module":"target/main.js","sideEffects":false,"description":"A framework for building web components, and applications with web components.","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"wtr **/*.spec.ts --config ../../wtr.config.js","build":"tsc -p tsconfig.build.json"},"peerDependencies":{"@joist/di":"^1.0.0"},"optionalPeerDependencies":{"lit-html":"^1.2.0"},"devDependencies":{"@joist/di":"^1.8.11-canary.1637251084.0+7c56250"},"gitHead":"7c562502b4a5ad481f66eff5b8c28855d8e77735","readme":"# @joist/component\n\n### Installation\n\n```BASH\nnpm i @joist/component @joist/di\n```\n\n### Component\n\nComponents are created via the \"component\" decorator and defining a custom element.\nThe render function will be called whenver a components [state](#component-state) is updated.\nYou can register your custom element either by passing in a `tagName` or my manually calling `customElements.define`\n\n```TS\nimport { component, JoistElement } from '@joist/component';\n\n@component({\n  tagName: 'app-root', // register now\n  state: {\n    title: 'Hello World'\n  },\n  render({ state, host }) {\n    host.innerHTML = state.title;\n  }\n})\nclass AppElement extends JoistElement {}\n\n// register later: customElements.define('app-root', AppElement);\n```\n\nOnce your component templates become more complicated you will probably reach for a view library.\nJoist ships with out of the box support for lit-html.\n\n```BASH\nnpm i lit-html\n```\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: {\n    title: 'Hello World'\n  },\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Component Styling\n\nWhen you are using shadow dom you can apply styles with the component `styles` property.\nJoist components will leverage [Constructable Stylessheets](https://developers.google.com/web/updates/2019/02/constructable-stylesheets) when available but allows renderers to fall back for browsers without support\n\n```TS\nimport { component, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  shadowDom: 'open',\n  state: {\n    title: 'Hello World'\n  },\n  styles: [`\n    :host {\n      display: block;\n    }\n\n    h1 {\n      color: red;\n    }\n  `],\n  render: template(({ state }) => {\n    return html`\n      <h1>${state.title}</h1>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Dependency injection (DI)\n\nSometimes you have code that you want to share between elements.\nOne method of doing this is with Joist's built in dependency injector.\nThe `@get` decorator will map a class property to an instance of a service.\nOne service can also inject another as an argument via the `@inject` decorator.\nThe `@service` decorator ensures that your class will be treated as a global singleton.\n\nProperty based DI with `@get` is \"lazy\", meaning that the service won't be instantiated until the first time it is requested.\n\n```TS\nimport { component, JoistElement, get } from '@joist/component';\nimport { service, inject } from '@joist/di'\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello World';\n  }\n}\n\n@service()\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return this.foo.sayHello();\n  }\n}\n\n@component({\n  tagName: 'app-root',\n})\nclass AppElement extends JoistElement {\n  @get(BarService)\n  private myService!: BarService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    console.log(this.myservice.sayHello());\n  }\n}\n```\n\n### Component State\n\nA component render function is only run when a component's state is updated.\nA component's state can be accessed and updated via it's `State` instance which is available using `@get`\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render({ state, host }) {\n    host.innerHTML = state.toString();\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    setInterval(() => this.update(), 1000);\n  }\n\n  private update() {\n    const { value } = this.state;\n\n    this.state.setValue(value + 1);\n  }\n}\n```\n\n### Async Component State\n\nComponent state can be set asynchronously. This means that you can pass a Promise to `setState` and `patchState`.\n\n```TS\nimport { component, State, JoistElement, get } from '@joist/component';\nimport { service } from '@joist/di';\n\n@service()\nclass UserService {\n  fetchUsers() {\n    return fetch('https://reqres.in/api/users').then(res => res.json());\n  }\n}\n\ninterface AppState {\n  loading: boolean;\n  data: any[];\n}\n\n@component<AppState>({\n  tagName: 'app-root',\n  state: {\n    loading: false,\n    data: []\n  },\n  render({ state, host }) {\n    host.innerHTML = JSON.stringify(state);\n  }\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<AppState>;\n\n  @get(UserService)\n  private user!: UserService;\n\n  connectedCallback() {\n    super.connectedCallback();\n\n    this.state.setValue({ data: [], loading: true });\n\n    const res: Promise<AppState> = this.user.fetchUsers().then(data => {\n      return { loading: false, data }\n    });\n\n    this.state.setValue(res);\n  }\n}\n```\n\n### Component Properties\n\nSince joist just uses custom elements any properties on your element will work.\nYou can use custom getters and setters or decorate your props with `@property` which will cause `onPropChanges` to be called.\n\n```TS\nimport { component, State, JoistElement, property, get } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public greeting = '';\n\n  onPropChanges() {\n    this.state.setValue(this.greeting);\n  }\n}\n```\n\nWhen on prop changes is called you will get a list of current changes. This, coupled with explicit state updates, gives you give fine grained control over when your component updates.\n\n```TS\nimport { component, State, JoistElement, property, get, PropChange } from '@joist/component';\n\n@component({\n  tagName: 'app-root',\n  state: ''\n  render({ state, host }) {\n    host.innerHTML = state;\n  },\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<string>;\n\n  @property()\n  public foo = '';\n\n  @property()\n  public bar = '';\n\n  @property()\n  public baz = '';\n\n  onPropChanges(changes: PropChange[]) {\n    const keys = changes.map((change) => change.key);\n\n    if (keys.includes('foo')) {\n      this.state.patchValue(this.foo);\n    }\n  }\n}\n```\n\nYou can also provide validation functions to proeprty decorators for runtime safety.\n\n```TS\nimport { component, JoistElement, property } from '@joist/component';\n\nfunction isString(val: unknown) {\n  if (typeof val === 'string') {\n    return null;\n  }\n\n  return { message: 'error' };\n}\n\nfunction isLongerThan(length: number) {\n  return function (val: string) {\n    if (val.length > length) {\n      return null;\n    }\n\n    return { message: 'Incorrect length' };\n  }\n}\n\n@component()\nclass MyElement extends JoistElement {\n  @property(isString, isLongerThan(2))\n  public hello = 'Hello World';\n}\n```\n\n### Component Handlers\n\nComponent handlers allow components to respond to actions in a components view.\nDecorate component methods with `@handle('name')` to handle whatever is run.\nMultiple methods can be mapped to the same key. And a single method can be mappped to multiple 'actions'.\nA handler can also match using a RegExp.\n\n```TS\nimport { component, State, handle, JoistElement, get } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component<number>({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec')}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc')}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc') increment() {\n    return this.state.setValue(this.state.value + 1);\n  }\n\n  @handle('dec') decrement() {\n    return this.state.setValue(this.state.value - 1);\n  }\n\n  @handle('inc')\n  @handle('dec')\n  either() {\n    console.log('CALLED WHEN EITHER IS RUN')\n  }\n\n  @handle(/.*/)\n  debug(e: Event, payload: any, name: string) {\n    console.log('CALLED WHEN REGEX MATCHES');\n    console.log('TRIGGERING EVENT', e);\n    console.log('payload', payload);\n    console.log('matched name', name);\n  }\n}\n```\n\nIn addition to knowing WHEN something is being called sometimes you also want to know after your handlers are done doing whatever cool things they did.\nJoist handlers can return a Promise and you can listen for when handlers have \"settled\".\nThe `onComplete` callback will be passed the initial action as well as any results from your various handlers.\nIn the below example, since `State.setValue` returns a promise we can just return it. Now we can track when events are dispatched and when those action's handlers have been completed.\n\n```TS\nimport { component, State, handle, JoistElement, get, HandlerCtx } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  state: 0,\n  render: template(({ state, run }) => {\n    return html`\n      <button @click=${run('dec', -1)}>Decrement</button>\n      <span>${state}</span>\n      <button @click=${run('inc', 1)}>Increment</button>\n    `\n  })\n})\nclass AppElement extends JoistElement {\n  @get(State)\n  private state!: State<number>;\n\n  @handle('inc')\n  @handle('dec')\n  updateCount(_: Event, val: number) {\n    return this.state.setValue(this.state.value + val);\n  }\n\n  onComplete({ action }: HandlerCtx, res: any[]) {\n    console.log({ action, payload, state: this.state.value });\n  }\n}\n```\n\n### Dispatching Events\n\nIn addition to calling `this.dispatchEvent` you can also use the dispatch function passed to your render function.\n\n```TS\nimport { component, handle, JoistElement } from '@joist/component';\nimport { template, html } from '@joist/component/lit-html';\n\n@component({\n  tagName: 'app-root',\n  render: template(({ dispatch }) => {\n    return html`\n      <button @click=${dispatch('custom_event')}>\n        Custom Event\n      </button>\n    `\n  })\n})\nclass AppElement extends JoistElement {}\n```\n\n### Testing\n\nWhen Joist elements attach to a document the check to see if they have a marked parent Injector and inherit from it.\nJoist ships with a test harness that helps you creates scoped injectors.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    el = defineTestBed().create(AppElement);\n  });\n\n  it('should work', () => {\n    expect(el).to.be.instanceOf(AppElement);\n  });\n});\n```\n\nIf you want to make use of mock providers you just have to pass them to your TestBed.\n\n```TS\nimport { defineTestBed } from '@joist/component/testing'\nimport { expect } from '@open-wc/testing'\n\nimport { AppElement } from './app.element';\nimport { Myservice } from './my.service'\n\ndescribe('AppElement', () => {\n  let el: AppElement;\n\n  beforeEach(() => {\n    const testBed = defineTestBed([\n      {\n        provide: MyService,\n        use: class {\n          sayHello() {\n            return 'GOTCHA!';\n          }\n        }\n      },\n    ]);\n\n    el = testBed.create(AppElement)\n  });\n\n  it('should work', () => {\n    expect(el.service.sayHello()).to.equal('GOTCHA!');\n  });\n});\n\n```\n\n### Use with Vanilla Custom ELements\n\nJoist components are an opinionated way to write elements.\nIf you are not a fan of how it handles state management or anything else you can use the individual parts in any combination you like!\nIndividual features of JoistElement are exposed as mixins making it easy to apply functionality to other classes.\n\n#### Use DI with any base class\n\nYou can use Joist's DI immplementation with any base class that you like.\nThe `withInjector` can be applied to a class which will make that class an `InjectorBase`.\n\n```TS\nimport { service } from '@joist/di';\nimport { JoistDi, get } from '@joist/di/dom';\n\n@service()\nclass FooService {\n  sayHello(name: string) {\n    return `Hello, ${name}`;\n  }\n}\n\nexport class MyElement extends JoistDi(HTMLElement) {\n  @get(FooService)\n  foo!: FooService;\n}\n\ncustomElements.define('my-element', MyElement)\n```\n\n#### Use properties and render however you want!\n\nMuch like DI, Joist's properties feature can be applied to any base class.\nThis means you can define properties and define how you want to handler rendering.\n\n```TS\nimport { component, property, withPropChanges } from '@joist/component';\nimport { render, html } from 'lit-html';\n\n@component({\n  tagName: 'my-element',\n  shadowDom: 'open'\n})\nexport class MyElement extends withPropChanges(HTMLElement) {\n  @property()\n  public count = 0;\n\n  onPropChanges() {\n    this.render();\n  }\n\n  private template() {\n    return html`\n      <button @click=${() => this.count--}>Decrement</button>\n      <span>${this.count}</span>\n      <button @click=${() => this.count++}>Increment</button>\n    `\n  }\n\n  private render() {\n    render(this.template(), this.shadowRoot || this);\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@1.8.11-canary.1637251084.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-0c8Vm5an6rYoYCc5WrpxuZVLRkH2ttn6osye7BtkFarzkgBNuFZOo+EU6ux+aPYlbVWy8SRASqp6z3PLT/HpSQ==","shasum":"a74c247bc7fa9afb7875a613db5325589b8ac635","tarball":"https://registry.npmjs.org/@joist/component/-/component-1.8.11-canary.1637251084.0.tgz","fileCount":32,"unpackedSize":57656,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhlngOCRA9TVsSAnZWagAAwTEP/R4wD3vpbky5z/GJ0nLo\ncDA3Wfp6n6FOgeIegtIKMaT8NqF0PijO4TNOhFq4Wkc32FqvmNfAeBtqtBBY\nM/C4pBOTaqKJg5nDgX2m9oFtqjVjZf0rj4kjQ+7IRM87KwPW+VxRiuORn04d\n6zNiVfFjRkadcPNf+bk5ydTm/g20p1G2Km0yWX7Zw1peY6OPwDKofzMg3cr3\nc7vUYqsGUgpOtW7QdppGq77ZkYIxKifxKNCOWWZ32QmP0dg5YijihescGII1\nDTxRre8yvso42GpMfkdfmym/gYn3mTKXUcG5k/kApStxaqgdUcMJT4ze9OS9\nDpxMolPI2i42AZz8U0+XepB/yio/dv3PwWJp317dOv547wKRA7hgIVp9jesB\nsA2wwxFzEHNKAfn65wqIW4FeMwnhaTYQzBmU2pQ1HSvcsa3pARWJew46P+6v\n62BNCSpO1AhCt/KHi/snc8qX1cLOk++HWIg5x6oxrxGnUOIR3KBYxkRdpE5N\nAL+zO7zjUkkF7z3HOzpQPgYHJU76HHKy2Ulq2Rt6fC1R6GcXLLdyfmwQW/2+\nlOdPc/37Dhrn2YTdpBWgwCdlnOTgxqe6SDdybMU8ffdfurom0HBuKjcqYxtN\nv4FIVtqYnDyb+jiPuygRYF5Olv0wqRWQAPI3e0lzGpyBT1otyQoRRCT0M4bJ\nKtRM\r\n=T7zl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDad0gzDFTPrK+GU8eaxBu5oWvJENoRnpIZpAqfUmkMSQIhANRFhn4BZ4+MNFvD7n0lZ644Un/kc3pI4ahrkpPt8O/R"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_1.8.11-canary.1637251084.0_1637251086681_0.8498120806918301"},"_hasShrinkwrap":false},"2.0.1-next.1637555722.0":{"name":"@joist/component","version":"2.0.1-next.1637555722.0","exports":{".":{"import":"./target/build/lib.js"},"./decorators":{"import":"./target/build/decorators.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"d009020b7a89ddf39b559ea30b981d6c834b3581","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637555722.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-R9iUr2/WNeagG6yKsNhuTlTxnahK6f+NQjO9qLIuu27fQQBQhXcU5GA7qdYoIL8eU5a7Xe0K3gGBgKaQlm2lYA==","shasum":"63aa1bace357544d93c3e5aea09835af8b958fc1","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637555722.0.tgz","fileCount":18,"unpackedSize":12628,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmx4NCRA9TVsSAnZWagAAW0EQAJYjfqQ80rTYV6ytONWA\nAsuuiLQoPe6ty+NAXHs6wE9JDeRcugNeOTZf5/PnCszgAf9ZAnGbTFW9qnds\n/VKJUEAcuw04mIh5TR+Ndb9v0x0/jLJFRzyn9fxgpNXgx4EuPEbWpD3FJhPn\niYoFJqJkau+U1UCOozPK7UyfoJkcjoMEvI7ivXwazgkGHV5F3fhS3o+3MaHq\nYsxHVCdyvZP6QXMsP1cTZYb6EHyMK4GILdwJCBB2fW7Cx5vPKmKHLrJL3Za4\nWBsVdh+EEORtgv8SzYFGyRSwyHm0yoKTHAn8rkS61/AHNTwxeVv7Twq26oSv\np9ofcDR5BXOhF/PKtX8GtH9wDWnbgIJGug+Arzr4LZ+dOZHKkCfEZPhqmREc\nS3rI8VbwEmlBgQZ24RT9XXldSEMfgpPUJQTQIortfepwf9wcd9M7zeCgY+Pw\ng0fFIg7dZTeGKJZiyLaM0Owo/qS6OT6QaK4Al+SstQVstGYZkNBHwtT6P/J+\nQqniGOgmPWrStDPjhEou1KVYI+vxofV9iAh/5pZw/O2QevmaHSvbg0GzMKrT\nHQg2YzC4fzleUIvNWRCPRo3TRJdkeDn9ZcSDU8A3o9F52eIggk/yPjJizGO7\n+Tmvcp/bBkSse1G8bTgEj0IEMZJDM6/PSAgoqgA5UVCj2c+p8uXK3ncyPGy+\nFtfN\r\n=Z8vM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCs0BhCyJd4TVwHJIgMJ7PmuH/psa9/lWl2lSDdn9oArwIhAMEU3J7aajp2BZyHwe8uBi1L00wsxjsmf8brkb4+OFRM"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637555722.0_1637555724998_0.07383120012012179"},"_hasShrinkwrap":false},"2.0.1-next.1637557002.0":{"name":"@joist/component","version":"2.0.1-next.1637557002.0","exports":{".":{"import":"./target/build/lib.js"},"./decorators":{"import":"./target/build/decorators.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"bfac94198ca3545f624115ee2bef1b5384140cca","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637557002.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-jvICnaUkc6TbgteNW9efxDJD1n/rSdTjYuzUL36ISYxiJyueUw2wZguidsVn+guy2l3sjhna0KIeWJoqsfQpvw==","shasum":"40582bd37e2c9e73bd79d7384eb7fa144d36c15d","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637557002.0.tgz","fileCount":18,"unpackedSize":12628,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmyMMCRA9TVsSAnZWagAAKugP/0FV4HV4jjps3hD0uYmg\nOlSv9wxqDDb4yFhYDERYTgXuFGdxMCgAF97sgSprP14qr+J+YfaNhVx3/8Pa\n1fuqQ4cLEarpInyQGPt35XnWyHUY8Pso/OHMeNFrh+9+8ZHDBZLU82fZrOVO\nhAxx/70dXxVMvp20wxpIxvA38VPu8uaf9cLR3SL7dAURVltdl9R7OmHoYdOP\nCPaUkSprmMkp6lX1bhc0kKtxFBiUec98YkhF6SEaea875Iln7jL/gpOhh0v7\nes1J4I715RzanbVSQ0opqmczPpO+7vmONWfCK7ZGQdHqK4N5XxQ6PR0wIgrr\nX8QTMIydYQ+iaDMyY+mzlnJoxZsfcLI/oa+2zcBeRMAlt5B8g/Gw9cYGY95R\nAx2rle2ifOgS3MuQa5RvCXnBVjq94Jh2mHHUoGfrUqo1lTuz1z/64WXEzuy7\nJyluLUp4X4ec/eh8gR9ZE6fq8nTWX9jMeb3hyS9b0x9l2q1mvehbvAN9ox9z\n2gzXxGS9nLlgqxipX48q5QxvTPEke1Pw4fxE4tWU+sJT98JtmMh6zTKd1a2m\nkJxeUBYxLITc2up6lpvxlSn1eXZ+uVS27/kZoJfbOQajcPLKs6o4+9DidQHH\n7A7+Y+pfs6tHkkEcj/pBv0mB9lfn9frBT2nl+p2XobRi+3v3xas3YYOkJI8s\n6PWx\r\n=+0fd\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCPJK4RR7nWdUpvrG4lfqCqaD+KHcKQ3CxeQr2jJauwSAIhALieA83Jvf2uPOQS5alxX1bfnvQospwjf1WdIUKogWg2"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637557002.0_1637557004448_0.13009705207191113"},"_hasShrinkwrap":false},"2.0.1-next.1637557415.0":{"name":"@joist/component","version":"2.0.1-next.1637557415.0","exports":{".":{"import":"./target/build/lib.js"},"./decorators":{"import":"./target/build/decorators.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"d1fca6cd9b40ca879297cc8ed3dbf5ce1b3c59b5","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637557415.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-1s3hds8vvgD9hNBh8affH92apN+JcTGP1LEL64aBZreev5mi2V7XB6c11Ra7GGjs9fjYPKvlGU5Y8PxHz3NXpg==","shasum":"0483e57b80fcdccc63b40338dbe9f4b9bc118441","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637557415.0.tgz","fileCount":18,"unpackedSize":12628,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmySpCRA9TVsSAnZWagAAEiMP/Rl0ary35p9ucOQLY2uS\nbZj7lS5y3FtXV3Ja/e9Ihzqf2Ijc5i9J9Kpwpzp+0s78Ib1uFyJ+tknWpTPk\nweXSSxb2BnL7NVu/+K+yz9mavV6eYrUSCIE5Rccm/nFkVOuQpJe//QEODyY2\nKUcTb3GhWzQzhujd607Q2kwoP98jE3NKFA0JYIRomNgtI3psCMnhoUrEYVoE\n5s9vMeD/1PVWSbx2nAzT9PFMW6bDP8r5ZXfMf/jkOTaZ9+YF9MBR99DLacQ9\nbsPCGkS/q1UnQv/4X7ac5VjDkPGgxVNunUGs/Sy8O1kaIhryep+oaX4xLSdm\nSTpIpad9AOb2RA0PX34R801eAEH+F5NliF8yDIvuFIwcomXcdgNXxCZ2fwHd\nufzLXmen6l6v2sobPtflpBJ+oNuESefynkyPUta1lRnWJYxdQ/I2Ddt7xwT8\npy/fTTYlT4oHzsTaKVEcS2MUubCY1nOUYzh4w53ufewa8jMGY0TWJCWeSgxO\nj1etb+30KzAICfJtu3zybSryt+0fa/PP+PDsN/nnQuyqt+9TFBc7OTmFCCqm\nHveHEQRSpn0fkJaM7s8MlXBTsASftUnQUUr/APWzqtPywUcG6fUEvXNbd1k0\njoo3p8vD/jIVjFRkk1Zo53ei6PuQ8lSzv5VrIG1sWz4SfN6mJx/I7NpUiBBW\nBGJM\r\n=spUT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDpawILt3t/G/wQ/Es4c9TF4AsSA2zyPgwS8kZmcv1jHgIhAKoNIXM54I/Md6BQYLy/ae+RyNdiShQPaSMqHyh4ipm7"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637557415.0_1637557417491_0.47384536015734"},"_hasShrinkwrap":false},"2.0.1-next.1637557736.0":{"name":"@joist/component","version":"2.0.1-next.1637557736.0","exports":{".":{"import":"./target/build/lib.js"},"./decorators":{"import":"./target/build/decorators.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"89a70ff10b5d767892ed0fa82be028b2cf7e7508","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637557736.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-lq0sY+m42xDtOrIAQFWazrqvGZZ4tcr4kOzhiximaP473mN4ElNSxAyGTffSf6YYOubg6z7ueJeEsJoHUfTM7Q==","shasum":"8aa7fa983964dcb858b620fd4159c5371598edbd","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637557736.0.tgz","fileCount":18,"unpackedSize":12628,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmyXrCRA9TVsSAnZWagAAUQMP/RIy8QI8QiVNLnA5lYSy\nxMl46BiMjnODzpnSkeppHSaux+uXi+FUbtYb5EjZN+IFHMlFN0wqyhV7n8rR\nqbKMi5qEo8kmUJaoST91RlMV7z8JPPr3EJoZTQycWgEW5gzIvLLdBjAb81fj\nBc4YyN6Lt+UGbl55fBQvm7o8zKiv4v5e0X1gHLFdmpBoZE0R7+Tbfi2Tur1B\n5ZYI/4x/sWuzfaKJxzBdUA5u//t3YyYdHQjrCZddVWUV/aDRYG1tfAj1rU7x\nFEkVzyAJo2HcPTMhiJTLfmUhCZ3kY0whuB2HsIMakLjM26EylXjEYkud0sck\nlzeEXI+TzWkcHL6tbM8AtW0pcobmLIIldiP6cLlL3/hMCrutR20NMA17pbdK\ngGNWv5RxI81KWn2g0lNT32+iBjg4nqEqgCKxirdh9AJbRx1wj69NfLH8/iIN\nxZtUBG1udpxtUs8R8NuPlcKSXYezDJQgFKOg+EopwHvhenjMcZp3mkTc2Emm\nPznf6m3XdHINhzUogweYq85xYrOblaQW//VrmmiJzr29sIX+JUari+KYBk5G\nEdg+M3DYBjyJ7oAujZqpntq9Fuy7aTpNOrmHO6b0bfXUVAFfrB/lsx00J37e\nkEOvuCaANq9OpBzoeZKkS5QFT4fbrdni95Puy8leo0cotpm+Nh5RfaN59sH9\ncrA2\r\n=2n2n\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDPtr3UKDe3yl/Hgq1920CegQkTM17+ugENXFvE4UwVhAiEA1oEHqS91eTjybrmHa2V0hdylV6Qa+u2NDqnqjkQh0Ec="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637557736.0_1637557739260_0.2927077644063001"},"_hasShrinkwrap":false},"2.0.1-next.1637558322.0":{"name":"@joist/component","version":"2.0.1-next.1637558322.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"bf525972b4eb2d50602929428fde257c9f8d5d8b","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637558322.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-L0agRGmqQjb33oDBbj2LQkvlsKPsYrc3kvFVirZk2WnT36zA4NYDczRWeiqVqPQ7RfGZ8zsvFKPZJ2rzFph5ww==","shasum":"13824f063786eae552c972b8dee3ff95f4ee4981","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637558322.0.tgz","fileCount":18,"unpackedSize":12579,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmyg1CRA9TVsSAnZWagAAqC4P/27+4aYOgs/ldrqRqHk+\nC0RQOG0Uq4XVaWCAbup+yY/UQ8HAbgFJmjfvAafmP1lMk7zv750o3Diu/ork\nrp/o+sdi5go9induMnbt49IL1jJBr2CDRmajbhgi0AsMAk8Kgx9H0Gke4gp/\nk0EmS+7TAgB5MsVMENaPpNN8wEffsj7MOycoLARuY83TyOPZrYiNoCTm5R6Q\nowdsMwloHm81vnqDiBGMXAUi898N+/hDfmhRlFHKjYFyQh+CzjqggX9E1aH6\nz3h7Cs98A75GOrCMBQlCiTmlyWYggcO0TNei7fNgIob5rhqTQmD2sHPA5jYM\nwlpqoyQVy5c+3AoFdxoY+Y7PQr9h9F1xa4lYF9F0B0i4ginxkQKqU0pPIctW\nqOoY9+xji8kNCholCPz2n3h+Svgf4cPF0LICdZ9hZmk+VcnWKVoAQdrWsZp3\nr/xFkFv67RogmnUmDPQ5yjIZDPzJP0ZhWW9K+BbezwuVxT0HRQWvKzp7KquV\nu7S2d0IuhSU0tIhBxul2jtdnkYpXf/dckuj1eaeIwot2l5V9cFH1bGLuEPo3\nVjYhjl/jxD2Qg6TRI+1t3qjVEzWCZFZFBW101DW1jnsGgvfmfayPlJfcEev/\nH+4IMTL7wabd4UhvpdksLAzwuT5Xz/ojulSVf2+9HHfbvUCLnj10GRcV8EOD\nkzHu\r\n=/0m3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDmcbGgWjaUdl50p9MXWQEf/bzgMLT6bSk99XeHFRibgAiEAiI3zgkCtyMivEhL0W97Q9OUcOfGfRxoHxNbd6nv75oQ="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637558322.0_1637558325167_0.021131303298798976"},"_hasShrinkwrap":false},"2.0.1-next.1637558585.0":{"name":"@joist/component","version":"2.0.1-next.1637558585.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"dfa7cb94044fbcd078c0aa89114e87e3f54fe8d2","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637558585.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-wAzDXp82uHAKSVkA8tLmkE4i0NFtot1d5995+dkyFPoGNlAHPc7FUF4e1x7J0ZCUma+SPvsLV2j0M7lLMQlnJA==","shasum":"05391c8b3f928403a3dc090f5819b8d5ed5425ed","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637558585.0.tgz","fileCount":18,"unpackedSize":12875,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmyk8CRA9TVsSAnZWagAAsegQAIHvfVXTpf4nH1TzwSRX\nAgvnnEhpe1fo5bE0ai3HMsMC1JF1+0g8LU2BDp+KVSlwtcGptH/hc/KyadlC\nIqqFFuJLUGamtKfndbdUK6D/Dp0lMKGHMB+NQxZwDVbOiKDN/O35nEdf83r2\nFM4b92SNe4sXAeRwX0raPj6340dC8cLOgF4sZiQDWB683zdq+ijeWPNLQhI3\nTjFXQON3+Uus8dAFnQvvcnMfn3QmVsRU/bVAikOX5ZOVyBUIYkXE9jY2qhBf\npnEsDnjf7JWGP/sdTpbc6/PaFrjM+IuA6G7XQUiP92zXQl1RUsanm4OpsTDI\njrQGYuaV8hS5hMVQrLil2CiNWd+I5hpuNIgrIHJTJ3OPhgbog2ad97WoRfFk\nKiO5GdQn2hwP5hp8V2C7Jw+6+R1y+Wj1rxRgCdGKROTX77F4BIXwnJ9b5K5k\n/7TP9q1B6cH//uJtrnpTC74WRUeVxwOVGI8d7tDdg9rIzTr2vQjwtFTMzev9\nqd1J+eQfGKL7OI/2OLowVluOUREcsMfOZqCf4K9ww+PuMKwPHGJa2sBKo978\ntQPHBgqNdY3xC/ZNt9EmXY9I5VTrFRrIhhzzJe4i1oIigL3YLHjTkXz5GVMV\nX8YrzmgsWY55rGJ+SRV1/xyM/TvG5h7BSyItQs359YRhxpuIk+icJ24l5EAg\nzrPM\r\n=L53u\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDuSg42yDkVE9hL7nx+7MT07/gneDp3DjQnpEmv6KDA2QIgUYiyqHMSndVOOGRoj1PEu2VJHve365KuRSMc92+eAHE="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637558585.0_1637558587904_0.08291404632839883"},"_hasShrinkwrap":false},"2.0.1-next.1637558883.0":{"name":"@joist/component","version":"2.0.1-next.1637558883.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"bd0ec3ad18dc06cde77782174ead4de8671ea125","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637558883.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-Haap0CqlN0YR8wwdxer1DW5gRVDus6a7kwjCvFy5XHQ7VT/nGbzkmoZETbjszSueLA7hflFKNVPCZOfXMZehWg==","shasum":"ce17e479c3f09b342674e513f1f775ffd5c98ae7","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637558883.0.tgz","fileCount":18,"unpackedSize":12903,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhmyplCRA9TVsSAnZWagAA278QAKHe6mzn72K5pvfmjIhn\nLkh2ACcDKjBPokKwwFkBAuiVTFnCWx/YMBcbxX5Dhp3phOiuq/B4wrYu3pNR\nPWS9g0rSjIbVhb3tAGV+ZPV8ukMkDyqDDgtxshApJJm/LiMazcOJQIGzwOsn\nsZ+eTscSdEBLAGpkTms6wAxgc9aBI/q3tWUPjB3Y1nPw3ScZ47GJ9dMCKDwX\n9depGhSdGlNlrktpQ00iMt2nEDsutZ82HCnJxeaUgKqAwR1D0vkgdM5PmaaB\nmq79PiuKr6b0p6twSZrG5Oh88KxWsj9sPL/ZPp2ynH0nAyMkLkIPGFByL44j\n5xYr/EbEBi8se7Ch5T3uHXi5QhKiOHZcjG1FKaPHJygB39l5nRy3jadshzUc\nepTgIQDzux4QH9s42TDCZ6IAwfriAPLfWtLZSR9VUl+21R2GaiAFw2o7IZ3l\naZpKN7pAeL8XkzxhCRyqZ0Mf1C19o5PyDI6wWrx67Im0YMyuZQytZX9XhdeP\nGy5AB9rYMUEm9nmncfvKn+x/kCNs2+4lT3zMRXZdkfoWtYawhsKIOusibxAp\ndYvP21P20xZu8BPUv4y9ocugKR5xlT9N4NAXq8mnfqyhosnuSmI2egyVtKa6\ntnns1BWBhlL9fUCKiMhttJTaKVOSO6sdalId31WMEmSauH+fXgcPHcLIC1Jo\nNEjY\r\n=d/f/\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBvSuexui3GQnVqyPH5k4a4iCzsDI9wo7g7jJ+iuCKt8AiEA+ze3rAFodpxWDtORGEgeDEA5TnupY+TJaGuFQEtu+DQ="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637558883.0_1637558885009_0.38571276275964594"},"_hasShrinkwrap":false},"2.0.1-next.1637592115.0":{"name":"@joist/component","version":"2.0.1-next.1637592115.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"22a2600447dd2ab93281c61cd2427f6872b28da8","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637592115.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-iMsMU5qY2szh8FrMhJAq2a+gc9Fp42B6oZl8kGLCPlBSwI/G9fE7u0OsJIaUC+S9EgPZ6zPFOLmaFHIJgZgRFg==","shasum":"6cf287a7a3a21e0c738d75ba963d6ad7790b826f","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637592115.0.tgz","fileCount":18,"unpackedSize":12903,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhm6w1CRA9TVsSAnZWagAALWsP/2A1wMra3U71h1D374yE\nJ/CVO1BMfTt2Rp7CAEHpqWr7MufFQRVKQDKhX5cKdRkZkXSa1W0CbBoSjH+W\noihd34vcgO7WxHH7qvcuuBx1fB1EuA2ZX4TSdlraZYSTNxCpf8ffj5Me3Hia\nSaPzbAf+z6PFM/4RQFqWIaPn0RA0CHoXARvT29iNetoKpkq+bGycqjWk98nD\njCyB7JttYZ7uLOV7v/dnYswlJu8osdh7kUZkXyEbsKf5V8GxI9sNPLbsFMyS\njulCOb9J7qU+70M9HDp8wp5Bxiv2D1cRbPVs81rumHfT2TokDxsI6MjURChI\nOt3OgJjg8wcFRqhC/lYO43zwPfPCm9fycSpI2qnYDrdK+vbTe56ZZcusXmVD\nPsIDdpJYq/kCn/t6JEYD/VTd38dGicA8NINuyngah8pUSzTbGhxyRhJzmc15\njWA3412UOAFLNckljrg/Y5qYHf3pP8pEPpzZ4E47CWUP0tod2RlM1BoXXtCy\ntsQVBvJJaqupskgwqia9xZgVLV3Z0xDU5VoLSVHZqYkdnkDaJLq2Huhax7nB\nd3JNEyBdoRMvfj1y7w4U6Ho28lQU5l5ewPvEOG/7QJBKac48f/kuMfptkFar\nUfDzY52PqPTy+jXkQv7bv6bBpFf9KWCFMs/spQZO8qy92DvPcNOxC155VrKT\nnwtZ\r\n=gC/N\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIAD70eo9EebxhJZfcbDgDyzv7G5+BZ4e2oiKdL0dvSe7AiEA9+g+EGgBRLCTa9RVHd4D/mdE0UXsmXsh05JRpyeB8gw="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637592115.0_1637592117033_0.6354835809292336"},"_hasShrinkwrap":false},"2.0.1-next.1637615403.0":{"name":"@joist/component","version":"2.0.1-next.1637615403.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"b06f65959ac5cc4f954ea39c8716e4ba69b13c14","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637615403.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-Nti2zkCZG1diQAF6Z4gWMsgPRLocylyZchTiYGgknLjS5bjoIwfmPEDnqXq6ee1vLrpaU0/zih5Nv6jDXX5wYw==","shasum":"2460bec7ff7fb1525ce743ba427f76fb013aada9","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637615403.0.tgz","fileCount":18,"unpackedSize":12903,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnAcuCRA9TVsSAnZWagAAqjYQAKDSutXVOoJgAMuOXAeC\nCpGY8LL8zNbnjgHSGlqa92ZK6kwORFdqNK0x7Q6jggpYjYPdksLmpQx0nt8J\nhmySa+qeDsvWwtka5jgEDueWSSQfhQ3C9rM4VuBwibMso7K0RmNr9tLsU1J4\nAQUY3uNNBZdqnIkybIWirCVhqcAeXEBwQl69Am14cA+sY/UUn0TfTG/CfF2d\nxtRL0f7To/dsgthArqmZznwVixYphy0upFCXIY1iqECE5qJpk4v5ubScOGA3\nIxUlP0X9rEeJZMdDwVbFiW0xfNd7oY4wBMoxhqzEsVxRUcLdbHXTxr0POc86\nRa6GQitXjuHCaEMIowypKysKhMI2wZZQ3A4ytD8IIKzf+QVHC3v+Oh/gQzjs\n/A6dVYZ2sflVVxpZ5qJoqZScbT4bUfGstBjNuL/Y/BTuUaiaUFnQ8CXMIQY7\num8Wz4h6R6aa/CZ9DYcBAm5d8IJOBqDndfa0WzXsuzTJwf8pBRcn8Sqk0FSs\nKHh1WAcIfFY/mZeoA1uFRhnS1nKzD1hvuSl13Bjb6xhYehRRjeJOYjltY15V\nFgbcxW8kyDnQnN+o8q324L5LMeAf0B5xxmyO5mjaCYMPdBdBJj5+0ahyKIn/\nQW5M+NRPFZOVjTe8uFKhnBfyPRfhe91kG0jxNen2oxVOgiykKdCpVwQiqnfN\nZE6A\r\n=Wn1O\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCdr9XoO14mM+fHFAv/PLR4ukvPM9RAsViHVckxD1m7SQIgU9WBdplSm3/peRb9I6Ez6xeqfmj8w2wb+Sy/g0rbLQ8="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637615403.0_1637615406154_0.48821216804083223"},"_hasShrinkwrap":false},"2.0.1-next.1637615494.0":{"name":"@joist/component","version":"2.0.1-next.1637615494.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"d9025bae27e92eafc663d99c411ef3eb8dbe0b28","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637615494.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-n5iOgAZ1qshvHAhjJbCAdVyL+6aougUKfhLYnJ9XhGWQWrvGnbsw3tTcdSHrCPWI/Is5hLgxXnVCxwoqtUN/nQ==","shasum":"9939bff458b8ae046c6c96a3ba80e84c4a8c18ae","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637615494.0.tgz","fileCount":18,"unpackedSize":12903,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnAeJCRA9TVsSAnZWagAAJaAQAJlkZGJsZIdZkdEelfJO\nOVmZcqxcBCcW2NWlk9fCUScYi7MB1OCkDVC/QqhWUKNqkCYcnw9yHqfWnvOj\nKXR8546QJQ/7u7HdXmYxrhcHV/8ymOxoQw4sh9LBw/HyLe9SLHlAzY60TIm0\n2PJimH+taRWYQTxO/eaJb6Foba2h9d4B+PrNn1oxWueY7qfRRC6SGxYpiVph\nQOR7guxlzhpznt9FkMuirCroy6/+Y/H2YfYbZoKt4aQOblzlElVfdfk+IDh3\nuJpjYmBW9+jdE2pkM73781sfObv7tDe6ONhA5Nf4651A6we6bGg7HrK3OL3y\nT8Z9SzRycqIb3bL1k4WVXiDNKKoYr1A97wsidIMv1DfP4qAjg5ObGWwAtR1c\nWP2YHOvN+GpLrEOwZZBL9SaGpl9snaYzVtcTHN1OLor+sEB4VKpRUZBehTNq\n8tn5W6j3L4+YxxKJoKUnoMvWjbaV29FC56L7HydT6ZRbsr1lbhycj4C09kBT\nkT8ZlAMoROJ26hg+vQeW3xNEj4dNCoATt/RVbb3XhdPxdFXUigrSj99h3BJ5\nt0qZEMN7CnH9uhR7SUXYaPHlTBEBjuxUJSkhtvdNV9ck00DMpFl2XVMkKdrb\nCV4vG76D8SJhDsFh3JVahO6DQdoNbg/uTDfVL6J2hq+gjmFp37nDg8/EryyT\nY5L0\r\n=VNyF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCH2pbjLg5xjnT1lHXDrdOHjY6yeCAG+R4crUH7UR2P4gCIQDyVrwmqDnSUQjkZO6y0DrmXIbF3LnbChXzjQspro2Nxw=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637615494.0_1637615497045_0.15253062702379117"},"_hasShrinkwrap":false},"2.0.1-next.1637615741.0":{"name":"@joist/component","version":"2.0.1-next.1637615741.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"bb5b07c7846970ce12868810aca2f092754af1b8","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637615741.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-YiEJlUoN+PkVQDOzSDlVkogkAsmy0Vy9LlaEfJCqo/rzyzfpniVyI0oOMeV4sjkYXFcaJWk3vWUD4LJCPsG8Ew==","shasum":"4fdecc0fbc4eae21a8a8c9682619243df10d83c8","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637615741.0.tgz","fileCount":18,"unpackedSize":12903,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnAh/CRA9TVsSAnZWagAAJBkQAJJoIRkuVVkNQePOt9gg\n838MdegpgGHJVzqWc6lj7AUQjyJs/T7HhCCodu5YyXucGD43Fks1E75Grjij\nRPKPCSRobTVMJ8sg2Z/rvsyFL7InPwCb8Y2xabiAH0c4l5DfrjaYxnI3Pezo\nQzHW5OsSxQiBZBmE45AtdYj4rpcNCdSMJv3Ktx7BtBLwUa4HkYIawjnWphmk\nfbLbUeBZ4blsZ0pO/o/7JJpipKCtIig20I4eXOrKXoJ6OLPJkS5z6oD5KFFP\n8M29PT+/z2JikO4EF3Yb64unR9QKt5FZr8X1MmWrQm4+9MFdGCM72RaPViP3\nt6H2FYgY8GNUmjAdxHSXf5/DEy6DFeT6mMvEDVnMhB9ps2GOJixG7UucvYUm\nWGJwIJ8uVc80w43JpBHp0yMRgByzyR6ubIRiz3yJ9DO5773eixriepCHlPOb\nBVKwIRZ9hHu3A9zK/qZBmX/VCt5ixZzuGe7MhYK0DE1naYYxtocdZEL5z1+A\nYLIDQVZwanDc/I44MdkzFRG8gd2Rn0yvYKC6Ci44VBBUNMqcpZBG5Xs4rtN1\n13riwgg040RfWRxVsFzGRSmp/9DJekAmCh9YMNGreKK5ifDW3X2AU5rTxii+\nouy1jKj8/SsVPndD80hyllGFpWGZSMrx+/aCBBnDdg2XsUfUlxuBx1Ad5u6G\nPUUv\r\n=VK0U\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGsV4iwnUaey/bZhx/vGR58VGZxsUz2yGm7J05l+Z0ukAiBBbAUSf1Wo8WaEl0hP6yTa0Hg1rWBY8mCz0F5uSFrCjw=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637615741.0_1637615743778_0.4080862021700755"},"_hasShrinkwrap":false},"2.0.1-next.1637616487.0":{"name":"@joist/component","version":"2.0.1-next.1637616487.0","main":"./target/build/lib/index.js","module":"./target/build/lib/index.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"22a2012e1c560bc75603cb138f4c2cadce3ca657","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637616487.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-a/41y5dmdNW2HIrcJIpOnfFob+yfbW71/LRj5ZljcOcIa19n3CgqjD0TZnFYNf20ypsUsjPC/2/mUh3t1NlZwg==","shasum":"ffdd43b54e2d2abbcd9a890a81c0f9721fb60980","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637616487.0.tgz","fileCount":16,"unpackedSize":9375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnAtqCRA9TVsSAnZWagAAxYoQAJZRU7w9EZJBDXIzZ3Qz\nq0QrlMYCX9312nLk6m+yfvZjPIiXd42QAxGCPmoS4X3mamj8pEsK3Hcfip8i\nmLoF1kMtEMXPFI3T5VEuSXpmLQ4t2qhgN/DOuWwlYChpZrW13tuq2IS4GwM6\n4fOGr3y45kvce7x+W3QAlWohK2fspX89t56obBeQjSr0iIhQGN6lFXfLGbN6\nNCwwHMUbjYoKFGkGbAVcMUkTKVfuvqkYtN4zS6Dj7sVxdp3nRpt7KgfyABhI\ncU9z6PuhRd3n1IfnsCNVbBy3Usb3IvgFLe4E34DSFVdFWzdjlWI8iio5BA6A\nPMTdL04jtYEvDML+2KDGQfWtVdh+2aq11/2momnUSnohNrVCFkSM+p4pU3eg\nACwMUrXhl5LK4TrpoB9OxLxy5aBc7Bs4JFpOTvi+Y22EwGOzI1QZk0hR6vOO\ncxsD9kl7+9DXx1Kfe75QEAorfBW71YPTFPk+4zWB9IDUPmTVSdKPeSW5IZBc\nduguc1lZMANMaylherXwhRhJYV+x3Mq24rvZT9dntrSBI/fcTO4LNqhWkqKp\npdbdSeZAZ3Lq41MzJgCHLiJODbMOfd2BqFZatbGYnXGxhPheBGuatjDlKlHs\nITNLM3FvkKMLom50MNOIYJMXCQFJGKeo3zByOXkBIUnKv+8jzrTFx+zjRC/M\nSbnV\r\n=rWAn\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC931/g15Lc4JRp5y/ACILnarYFL+B+FndR3mX7Kosm/QIgL1myxHl3xqllzje2Y0jSAHAhf+2hzFcth9BJKLThrOw="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637616487.0_1637616490196_0.1255018103961989"},"_hasShrinkwrap":false},"2.0.1-next.1637619197.0":{"name":"@joist/component","version":"2.0.1-next.1637619197.0","main":"./target/build/lib/index.js","module":"./target/build/lib/index.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"80af3982cd57059280091e36675fceaf9c0b4bef","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637619197.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-2eLH6wclQm/PoIR3YeEgLaloFC+wAc7hs8p6oo6JRf26IhZVZ/K4fRJKPl4hwwwNA6nJkQ6y5SneH09WMEm1yQ==","shasum":"917f90e460e82bc0097c69c39b11e0f86554a28b","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637619197.0.tgz","fileCount":16,"unpackedSize":9375,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnBX/CRA9TVsSAnZWagAA/CQP/3Du8RAqtkvvXw+uytlR\n9vQPxKg8YtwgUccyHyMznix7/5r+AhV7GRUlvV5GZ8dMCFSOcemYqMEH9Plt\nzRTa01ZuJqS+CwxO684S31JgiwXtbpNvSz8aVkj5AgRlGgKXfNXas2YMMkUE\n2m79kN1XVFD0E2SiuA8NI5SmjS50COMZUXNmO0tChygKaRKs5AQwR58MFQaM\nxpPNETRPXl+MJSNjqZVYT9Bm04Qpmm3TiRsjLdZLIwQGvXUOgaObDO7Pf+SS\nIaQfGdMSRcTSl+Jywo6FXD+UIGKhT9uI4vDH+QnD8pD0SMmE7Lvz1PeDCrk0\nFLOeTVDLEnAavvbi9lNS5ljqkXDsbdRgK2C8DQ/6f/LeuvLheYUOtE4zfvsm\nId8Oft1e2a7v8e+cWAX0JLYjscDrGsQQ6Z7bo9NroQb+F7KnpgzaPch15Y2F\n5uL1sUQMI0w/5X4vpq/Sy4u+R1cwnqSH9pDRaZLec0ElaGxz0hMV/XvQSYkN\nkU+eGLlhiFYSoc6pLYtHkCqaJhV9WRSPKp5/PJMpoR5ZJR4q+KJP3H5m85Iw\nPq5cQ86Rtpndq9PlXmaa7Xrcb4HMoKXYPCnIekk6EUvObwxWVbG9bLswgHdX\nAJhTMnekZRJiwJHDG6c/CvZ946pJq+eBfKyl2e6yN5j+3ibS0qdZasJorUVF\ndZML\r\n=4git\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCn3dpPxFid0RnAyWa/+lIzsqqZFlHTxbOXRVmAj/cgAwIhAPTBVnIj82WU1LMVVoJ0T1XMmZzSzNGdkoNWn1QyWhyW"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637619197.0_1637619199685_0.3968456711094386"},"_hasShrinkwrap":false},"2.0.1-next.1637678584.0":{"name":"@joist/component","version":"2.0.1-next.1637678584.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs","build":"tsc -p tsconfig.build.json"},"gitHead":"fcc2a0cdcb98efd204a8220a8dc6702369374487","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637678584.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-1tPaPp2fbXixa0YLro+0xnh36HePk966bsijpPXdyaihA2NvU3R7UwMICK4WUsN9ouCSPIIBTFTQluy65B37xw==","shasum":"3c9ae13f2f31315995dc2ec9b67337e51692bcad","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637678584.0.tgz","fileCount":12,"unpackedSize":30714,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnP36CRA9TVsSAnZWagAA5nQP/30YtG3U6KnFMiKFfnBa\nOgKVa6EYkjkgxoyvESe4lVYwOGu4F3FXRqFNxEWklhtjmDApBOo18TGFOQaN\nYeRUG0DCLc3GszYMr2RfyzkvCV3xNUIiE8Tz1672Qq+TlwLg8fNwtXe55fKs\nNPOqUZiPD3CDJQYwMKsNE9RYGeReFTH4BuAK3ZwuTaZ7V9O5JQqKWNPsHzAO\n1v5lyPv3+Z/K48h9C7UdkZMRjYKoAbzULOtLU+W7viL93Cqg6fiFiuSiZeTf\nh5WsQCdP7tIeDZIX0EZl+cd0p2z/qeSoeXoWB/UV94Yo7db6Y+0YvkLluLfO\n5nvU6bwAnqbPYa1hVW+vhRt4sGV3lM+nCNLnwXOuq9iv+yaqJ9/3JjUYxQ6l\nxNbZdIbIPtPXAhH8kyZIXILueclYfZZy6a5eAc6JAWn5NlCxC/q5CYE8eKHj\nas2NrzkCz1yTP5pUwbxaHOI1USJqsLMiuL8blYX50qxpJn8vIp37ZAhZ7OHa\nlgMLDePCKK0t3kd3cHu7+TxWDvYGfEMRxJUNCnI0ncKJM60sZ4ywyVauIkXP\nh8q048dLJAPZG45nuU0Kkmf5+/StrtsbtLDjPKlvX7h7tcjMCRCH1sEOgZHU\n3f3pVfHvG+s3B3UHEKGPL8ACAJzDfL26rbIuRPPaejVjQcqz415iWwEccnV8\ntGq2\r\n=Ejuz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBQ3x5923bHZhV3+XIt+I2l/9t1b6umZHk9JX2Up0SKmAiEAo2bJzb3w3RL/RzvUg5EGKoDI7BV4Iq9j7JK2n4DMZNI="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637678584.0_1637678586412_0.8872916767640149"},"_hasShrinkwrap":false},"2.0.1-next.1637679117.0":{"name":"@joist/component","version":"2.0.1-next.1637679117.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"a11f986c2a11ef39feecb0ccba85ba365ac5af5b","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637679117.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-BTJTqM86yHJpIVcBXV4G8Ut0DS84WtSdodp1XWPgnDpd9pPh4qjW1oxFTgA9bVUtXQoDZnuS6B7tcBw0eqvixw==","shasum":"b69908bfd47d15f55189b7cab0c63a6daf734a0e","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637679117.0.tgz","fileCount":12,"unpackedSize":30845,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnQAPCRA9TVsSAnZWagAAhsAQAKPz3S7BIXTzUeueVMM2\nFmeyQF13xtiaoXkUH7MzKM9hS8ORfcAmrlasp9yaBqZX7W+z2l1ViKqFAsIz\nLZKBGQSZ0izG98yVQxDVyZVW3YARHvGkfohok2oCTHPqz8vFEP3BiyTCtSwQ\nOILNr/mlpk0nPxXtwsEUNnXy3R+irmA/KAjIvgJBkbS+ii7lGpk1Hh5eTxKV\nTRoj3Is/NHncJcMsQa1xDp9ARYa2zZx7pFDJ2uulQgO/eLcbz0mLsFlN/jc5\n+wyZ/oGT4gCsgk//jT/XLnKgaK4lpjV+efF24chlu/bCmcalyf1S803A87IA\nJy4CfBmyX/nGm62yL6Mcynn4FiKR/JX/w771491OYruVbuI6BmrAuwKy9N1e\niygEO72RTBitxq3AjZH5lTsR2SmGtvWISAoBWweEgCXuarkYIYpGyoFl3VsP\nLa5YFNwBieP1/Iyz7RRuAAXX5Y/1MrBlb/EIpQ1nvY9/g7P6XEOwSNOZiFEe\n7CuNmV/Xfw2cLzfQX00jjBk4/A9Mg6T1XFPSmeLgdw/ARIQxPI4UrPgp4o/M\nwGrwEl5KFZ5vR2EZeLXhwZOXgrCvccVdc0nb0m0p4Vdw4J1rICmFx6JFooZ5\nlnfhYbQMXCHFCzkIH5I2LIQHOG/OGJ2PW8ZVnUrqCcvINoRxtF+n098yaeh6\nm7cb\r\n=i2RL\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDzl8t0srzcfVa1LQm8ZraC5V0JiLV2xQLeF1SqoChn3gIgebS7Prv96uJLa5WPgR0d8MGvTK3PtxE7PlDvVnCK5Ks="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637679117.0_1637679119397_0.7955561490758423"},"_hasShrinkwrap":false},"2.0.1-next.1637679901.0":{"name":"@joist/component","version":"2.0.1-next.1637679901.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"6507a985b9d7791f62c682bef126ea1116ea0c36","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637679901.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-hks1ODL/tUj73ibDNa1lOTRc4BxtLIAeIqpbgu5EC2X0vUQSbuv2lDX+mEG+OfXTN6/qvf0pBAwMJ8dRQDky9g==","shasum":"305ab1e0448473e152ce16907bfe848d5dc2ad88","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637679901.0.tgz","fileCount":12,"unpackedSize":30895,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnQMgCRA9TVsSAnZWagAAcgwP/2DxojPRCwc9oBWfboPW\nsh7Ajb9izPsCVSPiplijp5Y+S0iR9KOi+hSILzFKofDijx3vMEF1Xcf6NoJD\nD7GbvSXr3A0LAddFbQX2TWWHUm4S3vgwocNvALzxJ2jNVfdpBvoaJVkrH01+\nADWh75ujTCSvWlcATV52YEq21tWDUpwjDvBujGwNQY7GbGdDeLr0voiyE9J6\nrX987Lqb3rUfeIRkcjqooVsFzPBbZGNA9nIXt2qchAVInZhtiuyIy34GlE6t\nP/1Sg6IgF2eYEEBNtbXegXOmJZI//V7iskWevsqDkEdcMvW/YWmJavFKDVtK\nRqfhpp/TERuA6wPf8ZrJ16YdTvJCiOZEntd50AmFb9EzUVNlfRW/P2Z23Cp/\nLTaey64utRrbNORz05Sfj6JBxDTO3II6vN/AJJwyy5rB/My5cWyd5s2MMyWy\n5K/Qni+BWmF+fg+ggIFjUQHs3Anp0r03VdM82gb+FdBii5+0sg5i6LdSoZ2y\nmGsF1KuvVvV9Tm6DHhzhH/336oSTQj62uC0g4DDvNRjy63MbX4QNqMB/ujj3\nQAXZBhZTZyMXKIuefYScieHG3lY/+e4WsmSL+hVDqHnEOadFQe+zX1cgW2fX\nTXTozNrOdYFarc9CZ/HcDkaGjn1f2SChF5jMZfOCYm5dgz1VHCDTj//lOrTN\nlV3J\r\n=ov+a\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQC6XijLOjXMKe9O5+nRMxPGSijY3xEFDzKHxl8VjtY9hAIgTOgLne3zYSS+KrvGHPb80aLaTy2StFrUcOt/IvKxiqo="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637679901.0_1637679903872_0.43514499213892277"},"_hasShrinkwrap":false},"2.0.1-next.1637684016.0":{"name":"@joist/component","version":"2.0.1-next.1637684016.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"854a6309b6e3832c60ea07b50f9031ed99c774ff","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637684016.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-rWCKGhreVwcVSSHAFwBYQcWvKVf5PPqY7lXOpyoBe0of6kALkHnvN3jCpLKZwG5UpsM79QDwXU3hLF/1LFecyw==","shasum":"f807c9d9280aa8a8e5cebbf4aaabedb0fd2a45aa","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637684016.0.tgz","fileCount":12,"unpackedSize":30826,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnRMyCRA9TVsSAnZWagAA4vcP/1TJV6GA0EBfurVVlJ69\nMJ0EoFs4mHZ6Yaj8nfTcrsR12RPMPZ9LBvHTiEQkokZ0DD35JTzJz9t/ioR4\nPqmqae0KiPfFvOZ1vfi48Zrp1w61ugtxrTILBFYuUQztXW6Awy9BR8yJUeeB\nychR7cqE7PyfhdlSKv1aKFPif2a446lr6ZRl9LQiEUEKA8Llx51bm6sB72KT\nkEOOPdmfPZ01hwume1OVZnJCl96x5izD6KakoUsGXzVnM/xaP7tbX4Ps+Gxe\nKhYYRRJmhYdAwBbuPteLXANWH7zjoRcrndPpttl5JkTbW9DPZS+HV0Y4Lnue\nW/RAAM0A6FCPRrHnXs/lme0MpybbpJzPYPt/ET+INtMHXguYBGcXeKnZ21JI\ndbFzgC4pOd8XdjnVRI+p4Lte/ubBvbDvBeWf8RS83dlCei4mq9zQ1oA+qVYK\nPRmII5nl5SPG//RV6NIEkf1EffEZojuJC4ZZERpu8WszIpGgmJDNxiOyWl+2\nKMFF0PqExmH6lgpNY0btyCzdGQzt64pnVtE09mxHpyvhklzLsGwZLlWZIx/g\n/2iTUAxEcBlLR4FIKKIazVXiHnhNhcrj/Fx1Fi6BZ/RcL77F4a2pZpHe37Yu\n1t1+YdGvuT/Vaq2VQy/gTYdZUumOqtBQM1ng/UMYZfOe1sN4ewcF3zt9swlj\nXP1P\r\n=16Zv\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHOglOPKw5lmYIldpySvi2QKjIrEJ3pdDDSTjqcPAR/+AiBUXrMVMJsjg/EKiFe/CGNUI1OjHq13A2/TY2pbCtKD5w=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637684016.0_1637684018674_0.4262418467607827"},"_hasShrinkwrap":false},"2.0.1-next.1637688688.0":{"name":"@joist/component","version":"2.0.1-next.1637688688.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"718a63bf53730f35d28a259d56e524f07a756e91","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637688688.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-B5cMmA4U0+fDRaGEiMIdxw7GmZPxY0lTvIXa+UL7KsceLcsiVzvQWPAWyD6Mr7JAtNRB1S37uh9X2C2VFPXIGw==","shasum":"fb932a3331b5fbf86785d4eabf3a7be4580606ca","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637688688.0.tgz","fileCount":12,"unpackedSize":30801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnSVyCRA9TVsSAnZWagAA4NgQAKLBi/EDCTKhBZNZn4qo\nJ635euOLfS594UywlmbC4vQX9GmS7kpDOb4fa762du3xafD76mDXqvId39xn\nbQP7uJXuQcyDXxkVtLEXxZuIm0xW4XrxeYA6owp3xsA1ZQ45XiAYiLHBk2vq\ncZE55NNu1U9+tmD2U1uDT06b/DE9sWqnuvQQLvRzNg4XP0HaNCtHyfsDElz6\nE2FcGpYF5AsBPAa003qPSaqy2RI+Yuv8W/SBNPrNqAPgnOYq+esTlnY59tUV\nJCwaxtBfP723XEHaL7DCxPE3wTyCkkVWE5LlPu7Zbo45hVUKhSBhGThO5fSD\nuIVGNXtRpQQg/iQu7hz14OeeA7bYuFpeyMs6QjGQRG9vMGwqHvRL59N2bOBC\nI5u07btCXdlQ/iA8TSG+4zpf2LB1FOJygAi46qd35iFj9reGogAiNi3KSR53\nA6u9En4FltFZk2ovd2vHa0t3fUl7WhvxJNWvLuiSgThofouNq2GtWmrxA2p5\nuNgCi/3oOFsxoJmievKduivpyXw/z51/f7d32jOlMD+cRG86agSwcbxqQ1xU\nZTkmvu87y26gWIQJnrazedSiP4q4b55Da6JiCUpVr16qCiYbN7AbiVWOyaWT\nXak/MhM2WYQYj1w6JUNNcPaEDlTyBhN2Ukykannl3PgTB7p9Rgt77OqlIAuJ\n0h1O\r\n=DrsE\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD3nJ+oIZbNxLR+NZy5SfqWAP2S8z52w3CX1QqpNzKRXwIhAPc6W8XO9pkqFLNuI5Hd4sYy9DnFGBw6gsIAxJJXDTY9"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637688688.0_1637688690584_0.5966944002508787"},"_hasShrinkwrap":false},"2.0.1-next.1637688999.0":{"name":"@joist/component","version":"2.0.1-next.1637688999.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"4a7634c0f1a06c5b52ee643fe8bab76000aa83ca","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637688999.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-Z/B0B2zijerhtXirjScT46f248kTvwP0SLRxXd2hsgcfMKIZ4WBGP6YjFu+500/uwdBtP9XR1XkEji3n+8myqw==","shasum":"e0fba8baecd804b3ccd9b6c73b1c8d98c02d1e5c","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637688999.0.tgz","fileCount":12,"unpackedSize":30801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnSapCRA9TVsSAnZWagAAgE4P/2NBy+KbVDZ+/3bsinQq\nQA6Trf4uwRElOmvwqKXBtgiXXRItlCf117btH6pOuyMW9t10+iSQCa7Jgshm\ndTkmUIXHZlIutdZUvRNDtodyYpbSRVbSXLiDv71BvV8lk5ttvvVdNfvXrAGa\nJJ8AmaWxJgz4jcKiH+oaqXLbLN9D6sEFkuX1mvLWxykUNn9zrJtadmwBdCDs\ncPV0UlFm7wmLV7bjaVZeoDdrxGpLHZHmfhgKUFp1KPyu0EVsi8uIpvVuZZpk\nswL7SSY4tcR6ybjex7DQ3eTCtQI8+FiquqlBqkzzwSKJmWkdLEAABwGcHBzF\neMtU43qT79jyCxnkAnQKuWjnoY6h7GSz87IdHCJUI2SxDPhm5Eewa+ulXZbD\nsTJ+mgL9C0BDqLFIqY50qK+naB132gc2oupfiozJUpeHxH7L+UVfA7+BImLa\n0bbcW+Qt0l0qfQXW4XdVmp6hv7XF9A93jtbmoXPJ4oFBC/B4iFrfLhLHBi0e\nXD02wi6arAMPp2AyTuZqg7iROA5XiGxX9vQmQx8nqvd8TeZrjP4HHVKETAx1\ni+BuNjxFp0qAvJNnQPIuNBqAiNyhWJnKvH/7L/vH4IMvf5UTbpAQbNwbu29o\nkCXnMCLHTziQpRr0tBqQiDCUXamH91V9Nn1A+6UYuw2vMeMrANRKWLualkmb\nFDTi\r\n=2lpl\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDPNIOdoEohDUcd2CuyEcZFft0mOnM447ZsYdC3hTeqpAIhAI6XctpEpluPR2iQy2YJlh/KYRj5hF5iZtcySOGf6AgQ"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637688999.0_1637689001791_0.7859230304435372"},"_hasShrinkwrap":false},"2.0.1-next.1637728152.0":{"name":"@joist/component","version":"2.0.1-next.1637728152.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"6b74e5566332eff5d0fd8767c4190d73135c1d96","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637728152.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-eGTxAFGq34DPd/iESb0cBaSa9Y7pTdaHNDeQFyU2ar6zyrqbH4ojLn16nHHxeC/JCAexMuiBx9BPL0Saej6sqg==","shasum":"59ada4315c52e8045315cca98321f1cd125bcc49","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637728152.0.tgz","fileCount":12,"unpackedSize":30801,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnb+bCRA9TVsSAnZWagAAVO0P/0Epu6cUoiDKNPleroIo\n3//fILNGPpGXtXvslkZmKtwo5pM2SjDl6qU91oFdN0BeSnGYsC1J6w+7r1dc\nbjUaiu11AeaPVHErlb2QXtNZ8zk087mLtAE0oaVcJnOxiZQ91waVIIbPf3PF\nKy3QdxUOh1ffaMuxprjme5VeR6T/ufpC+0MDAwvspgyzAkHRjhgqZIrN0xR5\nEbvF+Omx3xH4hoNRYQDBGgjnU+13w+iNqgXX6asdzHR/5ugb66K8fN//kNlE\noBbGI9TbLJrJpcNIoh2c4FFJyOe6G+cWangdf9qu5U6ICcApcDquGAs7De4Z\nkSedrrJc61z3ENKkHr8DqvDxECoiuilxeiIdGl0diQTOjHROnKy8wlUtKfOa\nz7q9hb1+gfw0us7zWPutBkqFSIp7KIYDAHC0tHfjca5EqcbM1ttgwtFi0sHO\nN3H70nDEeKRiuwHysISJfzsl1HGE88ewjH1rqDhCEhxNNvhzMkAoI8KQ0Vfc\nf0YdObrKt5awpgrCvy6dmZl0FE7A3PQm0A46TQRaClOipqoCCuXvj1cIjIhq\n0lhjxvnkSWxjy1wqGBZgshW5fDyeGYPB6Bh4doN76w6F7+Ksj2ONKrHHoXMb\nGIReHePlMOYfX9RFAqMNAwcBgRxp/LLfYVFpkmM1oNZjeT4ssqZViXkk/TM5\nyYGX\r\n=qwKM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD1woD8xrIiurmFpbegNrF6XkSpBIFJPzXx6J1aTHSjnwIgcs/21eEbfvoIgksJMvtY8WOTpu62pyZ+q8l6j33ii/c="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637728152.0_1637728155746_0.9687957679202008"},"_hasShrinkwrap":false},"2.0.1-next.1637773272.0":{"name":"@joist/component","version":"2.0.1-next.1637773272.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"4b54bf516d2d8b1499106b00c5a6eaea911da860","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637773272.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-vJMjo5r4pf+caqaDEc7legyrb1pQlG0FqAu79zEyCEhIsb2prTjXN1rAEJbdR2Ptu9vtvMSGnmn5i/fYWqHnCA==","shasum":"61bf40a28a3d98218855c058cae8b71e150bbd3c","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637773272.0.tgz","fileCount":14,"unpackedSize":49644,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnm/aCRA9TVsSAnZWagAABnsP/i2bGwKvEe8s3iIn4U2v\nP+ZMV+7dkcIyiXP1tpC3KfvDPIX5RWI/SW2/sVjPS9xnk5F3ejHdqErG8ljv\n5FOV2VD6HPpxaZNAqsh/RMf3l7BU0Z/fYY8wsDDLA/Y44+lhc+dYhvQ+5pDi\nkVjlGqgYy9xMmtJCzItUXjQIX8V6Bxc9O45iXma0OxUwbc+cSyn438IHrrbJ\nMVybEcNUZXuL3NSN0WMasK11DOOQ/99jDpYYitaeJKiFR2DPdx6G22/GtAwh\n+VrGbt5G+ig3wIHHYtUcHHZapKOB342lFCD9qG6q+4shek3aNmqFM6/SKFx3\nDDK9iDetBfUIjyuh3LIMwMMhUJaTQNMWG+bSIAvUHWw5AaYS5ltNm8ecClgg\ndY9FzHR3DqRBmOF4gTMEhrlbCoTKOwPT0wLp29q0ExWSjgHOrdDlUpjGIPGy\n1NdYNkeSFbNa02atkpFtkJ7ei9dY0gYMRKQ80Ek8dEOAePfN1pxUWXnaNuN/\nUIARVRzSDRiQYL81ejgqn/u9evmxi7PAPWynf0ufUtSQr6aXAZiFWQ2Kfjgu\n3esixi81o9CAtVlyH1UMCm/G+kqr3YjShWG13KP8jbD0Q1TQ/mwiVpuQ92a4\n6AKx+ZaIpCp2+mixc4NB4xu0oUXoXclFkeYx2DMeXt1GH0eAFK2jKYgg6CRw\n0+X+\r\n=Lkg2\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEciCjDPW3BtZu4En9GalFEx4YtsWQrn0EMOjONmK78WAiEAuqqd70KWQBbgGiAeq7b4ENpiFS5VkzOIyuJy7hcejcE="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637773272.0_1637773274225_0.5131084936375481"},"_hasShrinkwrap":false},"2.0.1-next.1637776053.0":{"name":"@joist/component","version":"2.0.1-next.1637776053.0","main":"./target/build/lib.js","module":"./target/build/lib.js","sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"6937be526359a9b4f52032deda2c9999df4fd578","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637776053.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-MoydqySr7eUPp2/27SKNW3zPdugXfvCPYJda//XShaXiFNgj5A6YHOOujsucJwF179FMNuVJMZZ5loyerTNmIg==","shasum":"04c09b5c362ff96bd4aa3375011deeba1929f318","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637776053.0.tgz","fileCount":14,"unpackedSize":50110,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnnq4CRA9TVsSAnZWagAAt5QP/imBPotPL1SMhYymV2I4\n4RFa+AJ0NtKFaOaEl+5DbBNDdcKtSbmJ+InVo9Wj6QvvQR6GaVAbSGmGqU6+\no4a8+tLky7PH2ak2mFXGdAWtyk4yjesvsSqVJxY1xsDfx4bba+9NLsM6vZEZ\nQodL9So3Sxg0ITnApo1skVJGeTIN9DmLvpneIDfAu/ZZnx9z/bCEZpXrc9pE\nn+iir+Ta2uDwZiN/tXhTy6GKDXcREaUC2pocQ/YReJOKTLub/JYB1IQlMW04\nsM2HPhVR+wFiG9tq5HozR6djGUpqHZOg5OqmZSyzRLlHtbiOyEiUtmvNafCI\nU5z2Y3sb9wmFzkvtkve1OA3KyC4YL2Tert/YG52ZssyKsn1e0CgZTJAr2K+4\n8Zdc/MCGFP0bTIWBER3+VypKjEr5+H18LR7NvBxKHPVELGmBQsEo53pyQrM0\nxcrUCOGOzqCghxO689v6fe0jFBMaObCkiSOcN9EMeP3kmHm+u7cGEcvIOgrZ\ngO6FcPt432b8ZIsIxBpCHAZ0UHtYo8vIXaVFcBpLgEDL+XUUPjO2WhJy0wMn\nLKYHF8KFE6pfd9ZOyrNAE4znN/OUybdFpddQAo8uSF1Q+duSq/x5jroL/qgL\nF9vulZmahy1Dc9IpHR+a98R3BgQ8ggB3nRjf5LZLrTvkvira17uERDaXnFKH\npg4k\r\n=ksrD\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDZXVd+xr1Z03WGs6B2VzLpcKYTpwJ19CxqYM9Az8RpVAIgRzVBv60X+bi/SCKndgXqlWJqamPg1zK9FOjb0Tjrymw="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637776053.0_1637776055896_0.08934270151981405"},"_hasShrinkwrap":false},"2.0.1-next.1637783959.0":{"name":"@joist/component","version":"2.0.1-next.1637783959.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"cd33b71f6f5ae63eea5cec7e973de249c0ef98cb","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637783959.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-HmheNyv1dIEarPdZs+/0YAMiCyUZwXUQSbEHgs8uUJkV1vOsVrgb3DIRZJgEGbnQIQejl4Cg8Jj6yhaNf1T7yw==","shasum":"22d171ff7ec1e7ce9d5f01d7dd3b2c460acfb4bc","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637783959.0.tgz","fileCount":14,"unpackedSize":50348,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnpmZCRA9TVsSAnZWagAAONoP/0D5sPkTKQJ8MEH0JL0C\nrLFrPOxBVnYiqC7Zl21lOO493xYRv/5DXc1PIMQ7Jn+BZja6mefjIbBk+G2V\n2ZxtrssmOsnj/Zog+RBBddXZCd1PpYS41g/r6ctrPshoSdn8wYRrY4rgG/CP\n4xnLQRjnMwSy1WJcgE7XPMdDa3RD6miGuJM9U6pXdPBWD7D/SYDMWai6nnGP\n5x6sL8HLXuFisTyi8TqmD7f/Id+do/PFT2702QeK4buf/3XJ6cdZUNFpYyU4\n18n9qWBQWCNrpTePN8kVCBv0IFk9gNIaeZQM0bHdT3E3RUjOEGd+XyvUHKzq\nJJ5zFGbCxIJQUeYM03Sp4cdDgIEXcG5ALXBBxp0Jq4cXtk5U9CpeiQpBmJtK\n7qANfyCT4w4f3KtdYrybO10/02Utxi12rRWszVvQycIN6o0FyA7ZRNedigQB\ncipOvH01rgCYlnG6JNISq27yUy/OK8D4H/EDyzBG0/xnkvzxXaZO3kJLsSYD\nUwQ45R5nUtzsH5oeZcbdzKEpcUu1Q2K/ytDvdj8QxlUq8BNgDBjJlN4HqUgm\n7digVJpqx3aOsTQsmgYNrBpYQbi/8ycGti+d3fOTavGXtnB2LSA8HkTHU2b6\nD+8XcnLn6QtaKoI3qsiTZv2VFiBievyRmo+2eLvBHw9chOhGLClZtbB9q7am\nMM9N\r\n=580r\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD6q9E+2pW+ySLG6b1pyIB+lY9r30TL5BTZBAMdH/AfuQIgUVOWLulgszCskIdsTzL95QMH/R6KGs3N6u2Ut8XuUa4="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637783959.0_1637783961638_0.1404200007797738"},"_hasShrinkwrap":false},"2.0.1-next.1637791325.0":{"name":"@joist/component","version":"2.0.1-next.1637791325.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"65aaea9c8d9768015c92165768607407c09bfadf","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637791325.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-1LqBNjXgHFecx8DpZHX9K290VWHASxheTpQGxZ2wq6097kFWLJDvJZPCXP7z4eGwlujGNpNpbhOm4mxkum2YeA==","shasum":"c43bb34e73481c96589e718bee59a3d6048c7559","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637791325.0.tgz","fileCount":14,"unpackedSize":50348,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnrZfCRA9TVsSAnZWagAAOpYP/RCVl6xiR+AJf8Xph+vn\ndADuvfssGvtrglgSv529GgNM797/2ARa7PyPj0UNciNlb5Zzd9BDhOcMYmC6\n3Bik+HOG2wUsc0KCE10cxSVaoEVTvIWc4ui/cqwgAH6e5RQPeNpCTAQPLT43\nDA2HoPNzHnL0xrYc79rQpmprZV5GpKFb/bzAjZVqgjxVeqpdzFOSNBinG8nX\n0m5PkhBrpiFsZb4n4Z+2irpedacE0lXirqepJqZyVDlJmXPgm6FtNI7/OIAr\nelN0cX6fRyzCQQkS4Qrh3Qj1sGY/Dt9oLEp/DipQSBcEhephjnGmEGbi+QD3\n4Q0aFdP5E87UYQBSDF05obM/bIOaSxrS0nunG4Bu1pbTAAHyjPZEmpn+IIv6\npCqzf1XmdzKn6XpLfzsIzr3y8KsO6948BxPPxbnbgA8WmoqL/HcKS0nNDLmh\nfZDEQLhV2Z0sKl2/KBW0ZusS/ni3n/1bli6kWYm7mp4xzReZ6ttY8sZTKouS\n3t9zVwmGvlcsx1GWtV2lkggPDIJt7wPJeVj3NPqXuk+jlJtMtgB5nrCl48Ux\nl0rYP1d6KK6Kg7P1YgzZeiCUYF8cqoEMyARpPbGiD1aE9nqjTnYwFnKsDin7\nhveDHIwxj9s97XDFIoHCamELaDc07BZ2zwCgl3q7kfg4qAPmyC21E29uLKUg\nBQeS\r\n=Knpc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD+ija59lgIXei+eig/ZWfSBhAg09HH1GkDL40qbTnHuAIhALC8A3pmFaloamCGapiyg89Wv0ONceBPmJBd0KNcVL6j"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637791325.0_1637791327755_0.9969807677545368"},"_hasShrinkwrap":false},"2.0.1-next.1637802060.0":{"name":"@joist/component","version":"2.0.1-next.1637802060.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"8218c7d238a06776a6c63f22236375f45944cc7f","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802060.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-Eo/trm1LayexZNJOB+nuo/+Y0hnnuJq08m5RwfiWbvCRzuhJMQWvDp5zXv4vgsTPKrii4bMgHhfm7D5/KgBOrw==","shasum":"4eb77c7da48cda17e71ac198cd0c4e6bf121672d","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802060.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuBOCRA9TVsSAnZWagAASCAP/An5zLrdabpSLE+D4hc7\nRwFtzXqcHXSSHWy9DKTmC3gMFP6pSpY7ivExfai9dwdX9XjKN6QAaRpRgAdb\nbYZu9iPwakc3JhyRz50DX8k3JglGEh1SyPrADS59+DUE8BBymjVZKI8Ra9km\n1IaluG7dBx8vdM3ApM6XLuF72mLnQILHl5fzvqWQW4yllac0IwFnxzNGuKyp\nwt5lh2cQy6yDZEv+odfnLLASIxkJyWM23lFCcuv1A46eInx2lVAG9PILIqhj\nowzDg4wdlApCy0ariiMOpkD122qXyDntz+OBNVPSR6dDFS8seV3liEoKFFFS\nha1IWrlImiSH8KKmGMpusmkqBYpkaRXy0L7xi1Yby/pbnw+acXIQwx6T90ZD\nMPM+1E7LBB+nYQcqXBCpr2B+xPqhEeRF3DL03zvUKWZQdeyKJx0qz2zqm98D\nWOt6EGk8G2/8F51dxdxjgghjoOkcot2rN2zKw37bEMHfm18n2Gsn4FvbcsIM\njIgkC605ZZSDR21YiK2zYyKIuAbBQTvY1Ft+WYlG+WYlmzZu4lrJY49k6f3M\ngXlF8hWzEmGgwwAdmzPHQ2vPb9iQZIEOMstZrrPiBca4bvIsQCGmQwOajeR7\nCHJFqppJbvE2J2kPfVo9EeYeHBL9TlQfkUxe3JP0zwUNUspI4k4N/eCZsHVg\ncekU\r\n=+VPT\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGss8Yir8hBTIlVFoV8bIgzsT4u7w7MLw+bodEfB1uwBAiAoSa+cG/Q5tTYsPclXByaXuIeJ4NKFdkJ2UQ33RtdPeA=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802060.0_1637802062782_0.7728850809114465"},"_hasShrinkwrap":false},"2.0.1-next.1637802130.0":{"name":"@joist/component","version":"2.0.1-next.1637802130.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"e3c23276fde4234b73785dbe0ff245da0bf5424b","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802130.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-a8qXfXIEEhYCBUhqv8ZNPNpuCg6/+8MNpR+Za0KXirWiB9EXP75vAIGyTy2WqaK9ffPbQQAEOxBq8GZ68Dl8Kw==","shasum":"46b1eeaa7ea961cc0e2364ee020393858b129c02","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802130.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuCUCRA9TVsSAnZWagAAVrAP/jo1OlhzhOr80stinJEY\n/Y2QVPaC49gCz6rh40lrvSG0OS/i53pAT07csXz5Jdnsy2FCYdn0t94XL+Xx\nfR3+LK7OQ6JXPVkriWx+rn6lV3Zc0bnQe5zvewejg7wV4jBZrcprnjPA/Hdi\n/ub8OceLQ9r61eoSnN5O5RGwzq8H3ulWGjyZhiklV93uB51peYMr3Ls0ZDUC\nCfC2xQ+fUK9drpjGkzqq0gC4eUU4BF0jNenQ+ccM5vsOgsIZPKwRbaOspBq/\nxuc9yGomq0UMX8JpC3qxfPWMAx9WWJ3DW/TNxcSwghJGejFdHwM3iP2OJTO8\nn/5rngxx+w8SvqeCtT/OTyOXLXbUmMsF/0T2Id0CDeoBC4qyLtno5wdSKsI4\nu58BP+E/m2+MB1PjS12tzfeGd4TqUpBvtOGzgSF3KaM7rxf/yoLr3ABw7Jnt\n8CFfCB8GEu1iqvezqPm5du9l9U3b2L3ufqCvLbHgYcB0EbNRz0xVKE5NKCU0\np5h+qbwbqGbmkzZ9A5lvRowYAAJ6jnGxYj2TvAFkIMwgGLq4yngOxIe6Sxwu\njJ+DDaBuFyJhtilrHl7vnKDlfHcHj0NWsBmYSvlmDOaRcqEGDVtxS7mOn5bN\n0j+XlKmGRnHGE7Kp4a1Y9oVNN9c5E4BhG+YFqCG4J4D0SQEPUk1eg/14LS9Z\nXw7n\r\n=WC7x\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBzpb7D/GdCOYLxQX9oZIqasO9cHcISTk/33xIjaduxYAiAO1YQSDMUd4gLEoIIYlk+o6Cw28op2INy8kZCZCUcY0Q=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802130.0_1637802132773_0.13182913970129007"},"_hasShrinkwrap":false},"2.0.1-next.1637802244.0":{"name":"@joist/component","version":"2.0.1-next.1637802244.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"a389928113aef77672653caeb6ef7db65a1c63a6","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802244.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-QDKa7ngS882RamSIPjgzSdr2rcDK+skXdqIoTPC8BI19iG9aGGlwKXSCY7vyzgTiX5CZK0KlsD9uiKSYlSs7xA==","shasum":"ae8b76a4d23c2eda7d6aab2ea9672c9345312c88","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802244.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuEGCRA9TVsSAnZWagAAObUP/1Htleq7ck+BO/fJhVa6\nLSZfILoMY25HS7pA2ZACpBHdeXYrciQL5kxjZgowxE5S0y68R8lbG7YOAjdb\nnqDbwHKGZNQRgF/rG01WZJNTV7kn3XECLGdFTf5pKTz5FFV/2IF7dgptasPX\nlFho6THhT9hs8G8SvkEJ987CeqYtGKLk8t0CkHY3MhA0zaSnYG3TMdAeEIkQ\nVPNTOXvXWa6DwYzS+riURtUJdcex67+OkPaC8wv/Iccsg9Gw0Wd/llH7zdY9\n79g/WSl9+O1xov29T39BAwehQzWS3m+DpuhaN3VoU2ScS3D+hTfivQej0l2u\nCzDSabDw4BCC2zr7TaCZKvtIHus48gEMXhuoinmSBy0WekeUFXLjz41SLNtG\niNEWpzAA+GxUc7TjGEzOweWRigswlGD8YoV22jwsxTyu0sRLXv1w/8pyi6UU\nXS3fuIgHaTvvVjSAZMvnpaibhIQbLVUg0Wnouo+R7ojVsZXUuQ9LrVZOkITO\nYQRV0M8WTi528T9Tt1qbnexuLsQXmmADR0iMLSNZQm3KuO5tcjDKizyC9Vdg\nm8yzepVg4oPmlOFTNy1PKAt6LMbawtATPjN5uiDO2Xyy0wizrgEgthkVpv85\n1HjZtbNw4l/ig5RSLYwgoSM6eqlloOXguoTEc1THF4OZfXEQ9ByO/UR7t5lc\nIX+N\r\n=av+s\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHV4pzDqo03Z8XyQaIOmZ8HybL1vfb7GI6N8csCLh1omAiBoobZ5Qc/5Th6uLv84Y4xnrqYz7ctpMzRInz5+P8fNEQ=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802244.0_1637802246456_0.3411141903873487"},"_hasShrinkwrap":false},"2.0.1-next.1637802271.0":{"name":"@joist/component","version":"2.0.1-next.1637802271.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"00e554b84806d5fe3c8e7661d6aeac23e1361cf4","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802271.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-MSA/Ajqc/dzwZ5gc74kuywh6l+pCIS3PD3Q0WL6UWhiDfsxRMJIoROJqtzQF6J0XU6J1dCE5/B0p/M0WO1xZKg==","shasum":"455754749ad4dae76b5b1f9c4303f07150644a12","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802271.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuEhCRA9TVsSAnZWagAAvegP/1/m8YV7Zablm+nbLSCk\nQj99YySk+sscFm6eB1gkH46RA+7T4Fbvvm7dBHkiiIZaKUcs0yzuefvQ8dN+\ng72X6vp9hnd1JBa4m3NFFzBu1ZayBgAQRG51x/Zf77lHIbO3AkW7Rt89UQN6\nzkPr1wvivl0wtFnFKjsNnn+Kfxcj1xCdw9EdQ7x0BMCXX+pNk5IO1NsQcMSp\nTVWdPE9XAsAriDhWgwDPvoDblGmQW0H/7gS7jxaATxb6ARh6hz8juiplavzn\nWJKls1N5aZceVB2RaIU86KdlaSzYCO5Oc9rZn2s/gENF4TJR3gZmeevr97mT\n2XeuTpfPEmpzmkw7nfYbsiO9Qv+A049jtk29ZO80HXvybP+5z0mtjg/++u2a\nbzLko5PlMmDWucJptnqmGhlyU41VvnZWPSrm4cxKZdnKPKDXb1CZJoVVpKaA\nYdeFHo4wb1UEdVEGobNPMpjQQO+cbw+AY3vwPKRL74z8trF/J/oXtdD62hbh\nMnjMqm3mMR7sFcaQdm3QKxEpdUbJJKkyFVOCSVRgqVDCBBlI2O+I2U87kBV2\nL15wzjlMiDq5cO3Qt12+Dg5MKVx/FcNwUOrkW84hcqjAMjNoXQiAV04Zb4Ek\n0rDBgGAAUBLvCrzqCtco+mTvHXxg5eqLjQEc4Fotc0UFxOGIz29wT1wvonLY\nWbib\r\n=79Vk\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIDMOXK0QAQQ4k/7kitoAixM96hHrX0f0tHHWpLDRALCSAiEA3vdMbDyy3BwivYHp5ORngNm5Ae9X0UEIaWufYfFq188="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802271.0_1637802273576_0.5119943654386117"},"_hasShrinkwrap":false},"2.0.1-next.1637802201.0":{"name":"@joist/component","version":"2.0.1-next.1637802201.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"07860e7df2260889ec4f02c3ebc6fb5cd69a7ebc","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802201.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-Hz0lrs718ZVYqH1f36fIyY0Sdr1BJxx7EalDSmDc4eEFl13Tu4xtZHOKYMZIl7+E1jSXyIwlIKFNG7UYPqFBwA==","shasum":"c388a20de6a7c4f7c02a581f7e2a96c5521048cc","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802201.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuE6CRA9TVsSAnZWagAAnwoP/33sjAAxcQGJ8j/u30TP\nL04EomngDNy8Yxk9V8tD31d4jM2KCFbNCPxnIVeM8zaVB9xS/Dfqocl8WeXG\n52tqEWGTNT3plBfNbw8G7644U/Bvv9feaHNDJNefoXvPrK24vvu/u0nl+oeD\nWNhnOcSCxA71K0gWL52WMTjY89YalrXUyGii9YxfvNn57IaM4rZ814x/3wRx\nOHRwBv3FcgHHXQYNFHaR7FEnDl30OBjMBEZMadxPYKrlEw0USkDVll9UujJ1\nUFX6zpRCNqKuayJRR+vEu5NM/kZxKqwpg18NnOF5MCBXLQXvZkHaubuJPDsw\nfbu65mC5B1nTj8jxjKNA81hM9IUS1eY/rS6Gevld0IitUaDmAck9IunmQtNd\nkcQTxJNlyP1ouC/2L3aXTEiGxoFDPhKtHCkOk46HzybXVObTka6kotynGVG3\njW/74PHVT/PQQbDv/NvK4tLyp2KbiOB3ieEA6KF/fY0cz0LWYilrkPRlWpbd\n86V/mpeBX4/7BYQ+ZYPLIdiz0hfwBmbSXI6tQmiBPMkOtrdZq8VkYsHf24QE\nfYllSUfdMxK/ixiwalLiqo+Y0lrvxuFotY4bSoRJfYAVTWl5NYMEIeKzAxnV\n6WxzHI0lRfA66hroSAxGx/G05biMbiXYik3PU5lr9qC/DQJpYAcbU1duLM3p\nWLbZ\r\n=W7y1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCb3aZ3Vfduv+6brlwTzNBS8EE5y4uLshMEzktqFsxjXwIgdvu+80K9yj/0r7SyE5Q6lwmvJRaSy9DQ84u+hlvvWZc="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802201.0_1637802298851_0.41630010480357194"},"_hasShrinkwrap":false},"2.0.1-next.1637802368.0":{"name":"@joist/component","version":"2.0.1-next.1637802368.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"9c2c6d8fb8869297d6bf248194a7e9b01da7d259","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802368.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-IWPfflUZcmc2XPLei/wFiTIvejxaCgxMPRZhuICQ965BgEeXJhEQW0auvuegme9HQ5vzgAp5Ur9AXxKK0wSH3A==","shasum":"7ae7a41333838580d8140ee7f7a026b278380aa1","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802368.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuGCCRA9TVsSAnZWagAAYqoP/2hPyeyRIs16XMEBWgkn\n2ezYvh3RpzF0ltM3QM2TeliHgdT4LjOeItg8NiuC2lOB7Tp7QGd5l9/TQzPc\n0Vu1SvWmH1gbjlzaeixp4piQ30iZH/z70bEdfG2Omb9KteNVh17U8gZ7NOmB\nTk9PGnfOZ109dcZEFUUz45JoD+oy3zOGQHHJs+sb4vPB6eEhqGs6LBLj/Je4\nG9yH2UZl8rqGsQyS7ijKQizLinr73iqdOG7mZ8BKWbrTfIM4Ag6axTjw0Es+\n7jjkZXym69XY3tyldUGb3XdfkLqtDd30Dlri0vpwxxxRvSOQjVTfDFoAYfwN\npTehFIDvDQ/sHMkhHDnHo/zmAgseNU/xdlLfIxfdRi1k9vrKVZbh/eFAi+9e\n5ms0eDy9kQRpXTw0urQhomSlIy+m+rtU2vnFhJ26uOW/tJM61U+0DO2EAbnl\nhCtIHz5r/VgDElzUeWFsBixGeWUKyzXQKqz6HIt2fOOxve6FndCKVyj58Qj1\nY+UpUr/HSeC4BQKjzSgvtcCc5607ld2MXIIbhD523h4MP4TBnCNaZR9mcY1l\nSp4PZk8opvCbUPQlJrIkYRfwf3yMJ8VmGWfPtG159Lh59JbUwUUMsZZXxMfY\nwf4pBRtZ29M0NUR3n+MVIbrflS9s6370Cd/OVUdh/JQAcShR1sgnBux91rS8\nN217\r\n=st/I\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIC+y+JSHTB+CYJ4kB/r4887Cv+1dX9qSOxP1ikE4pDkvAiBWtmchycPNfrcHgNrSEq2TbxQ72snWKFhMTUU2/tc3RQ=="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802368.0_1637802370139_0.028941580083619023"},"_hasShrinkwrap":false},"2.0.1-next.1637802874.0":{"name":"@joist/component","version":"2.0.1-next.1637802874.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"61e7aa32cfcfeb602b4e6aec7be4dc05875f1696","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802874.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-uAyOk7mkBSB58TXJVRGQ4vwxk24I5zbBKYcYJLrlp46d33Ax1FD4Rx/vLS7vM//0MBCkGvS4p0jYR6/ZnUnhbA==","shasum":"d8c0d838778ae55a06443c6379ac13fb34c17d75","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802874.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuN8CRA9TVsSAnZWagAAVqcP/RQ/N75vXsy7JP496272\nLHpJsye3+HW61MNTEs0Ve21BDOknxD5MPppNxv2MsKCrz5GssEOfWf9CV+7y\nW6FpbnDcuvuQnZrxTcsVZUOVV7cyHUbA6TcxjLFKwGPp9+CnPXAPESQpJlee\nNf4y2nQswdknmZC0tQ+leiULWRkB06LpDp9gPlaz0R3Lv2GTIS023svsI/rK\nXGe7MG4UHwvqo/YIfGOZ+TtrTSFVJh4gpZf/MgJS41BtEXVdIp1TDLDqErjB\nllk93csM2lH5tt8oqlALsOAVUtxCgcH/mmHMU91udDnOc+jANojGZyqf3nKS\nuKobeUD/jG7SUfJRudj4oimbO21mk3cD7EC4ZFoVWLU1j8e7PCWCmH4LB/+y\nuVbHt/4Tq81sokbL1UqGbFJRi+jx9MxVTrD6FMxKLjEMMst5qQCuR4k9txpQ\ndS36E8a6LgVW35Apm6bHkAnN1N6WZ/L8AE76I2kT/zPi6ZlHbHF82Vdh/7B6\nsaFy5Xti38k1zHPcyMMzluiFoZP64BXLw+j/rh/BsLwFiwtBjWMWjfkxJTPN\nN7PenyX6SH07PlXORkncqMiP34NKnHcOOSfKMEfeY76Kj5Rvyw6lVWoUn/6G\nHGjF56KLAc8ICG0UPQtnSqgDr9ejNorD1C+UGbvY6TssnunWgQm9S4/h9c74\nFIeB\r\n=5a4X\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDByIUslQJoefNmCKml6OPu+f5gupaHW17bC9zbCthJ/AIgTiTsuVjVOKyu2eDRxZEgvazdhRc+Yn2TxtDTKB3WdGQ="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802874.0_1637802876417_0.4944439940837402"},"_hasShrinkwrap":false},"2.0.1-next.1637802923.0":{"name":"@joist/component","version":"2.0.1-next.1637802923.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"38e4524db03d55d8b70ec97d1ec59d6e2b49e354","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802923.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-5iA8YYIFHeM6sRKxEKcWCFy/RaVmCYXTciurNHXhcXNO6Nf8j/7rnFyfkt/Vj0PNqD+FM8CHLrgA79XB1cOryg==","shasum":"0ade80442fdb7e9c24c575dca613982181bd7e52","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802923.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuOtCRA9TVsSAnZWagAAzv4P/iQ4KX0BHHNgTliSnuWp\ngtQdzANhQJPaV9OxyxaENWoytA3orbxrNnJfhX0+ECdEwukOTrcRj0TroWq0\nrlOW6Z5OogeBMVsgtUfe1Vg6L0mKZWJT301ETUu10bHIqSPtT/9HURnbqrLZ\nKAgFmk/Pdk8E62ViCHS9TEPwQnxwRROWaJNQq72GAXAeS4PY+ZoRrTDx4XHF\nNcRBdmKv/SdJyE7+2kbZavQGMir6QShBoWlo6a7+X4Nvuu88mwehTk9aljGs\nFikrD6guLpN87wUwkuLaLY1eBPiWY01pnXCdeobrRB16kqF0owMtEsgJC479\nhIA2oJukUP6HsRnh7pTHLEHBBwRQ47D8/JdTpG+axTCml8wEXj+QvmxAsaT+\nxI1FGD+fZNw3qdpIj4/Fmt80EJNcgJgKNXJhBDGXQRMJLBuDsW+/D0dsMYBQ\n0J5LIEjLxvubVdo3JZqpSdMa+gfIFvhmEcp7t1RPq7OhtFTtqStaft8T5aAJ\nr1mqY/ybUlTceQgZdjpWeDOvVgYAnZhwTEPVZLzm3Mg2cmj5tKh8HkX+mt3n\nNuKo/wvOKUUi8JFmrWUVoYprwlbMoRIoqkz+Zv6ATzlOxLcBv5ZMnkKc4zcN\n/btISblQjKfJs7NybgPeJBwKLcTHBM/RkDvSX16w6pve26TjPRqs/khJhWkL\noEE7\r\n=t95e\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCuyuJ+YLrRW0kXCBiBmEAozPMxCBpMEgNbBa5LXbOGhQIhAOh9WxeFO8GkXT3hlQWE7vWVSa+pUDgIr0/zdW7vg4IV"}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802923.0_1637802925383_0.965966121064908"},"_hasShrinkwrap":false},"2.0.1-next.1637802985.0":{"name":"@joist/component","version":"2.0.1-next.1637802985.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"62efcad57c893451d53908049ee1f09b3f5daa02","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637802985.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-wbiovbcB5ovJWd4RgprzuMJw8+wEjlEpPStoC+VKo1EuWWgz1haSLrwKtF+eY6xL0o0W1wJf1CwAyLOzPOKPyg==","shasum":"957c20519ae04a2fa4e2f2c0cc12225cb1a86336","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637802985.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuPrCRA9TVsSAnZWagAAL3oP/2weeO/iq4On9CVBxMWD\ngygrs5Bar/E2HQ0OQA87dqvjEBU42vfd9wG5mEZOIdTtdCQcbfcFJuUblWhh\nC8YXCUHdPpvXdGPOBHCmGvrfqf0d04B3pl/duUKmQu6j49vT4+Ub1DVWjSnk\n43HkHPFgY2JXdmDmzOQue1Iogyvw13BmWzUQNY8BZy/BOpnrjWr8P2hb88QP\np2hKZXvL1/kt47jy4DRvtJtnepLgzsntUHivucxbRvTmH/AAsYteC0/hbnwq\ntU/9esjAAFxFQIhWHbyUW/udPx5HPkGbGRf79/jhW/r937pgJ4voMKiSOGYv\nw33CRCxPh+NVSovE1RvqHNYGC2cK3Xyv1qGSvtQYifuYxKKyhHjAygb808Gg\nfZ84XtgBj3dWN2xrPwniwIPoptRdYvAUN+e33SNS3womMJd9xRl4jFFo60Oq\nUq2Ync3ZS0v3OIRxynJ1l/9BJrlfAohcySW75AG0wmeVby8yaxS4gS/edaPe\nyj3J3xuBgTBABqDpwVb3oEVYqv3j8UWc7e2hRAckLf6H5cqOZf/FqFS62YNS\nMVIGyBcgnbi7+lgU7oixswTGhQ/t0pxt1e6MZCwvOZvxomhNik++eDpJ/zSm\nZEiSJvpoPUjkeT1u7wa5DIs3jkXUM8pzU/YwW91KwHg4H2RwxBHfAr6v3Xie\nyqK3\r\n=U6gZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHa2rAB4HLkKjkalhngDkNMhpcfNTMheeLXKylIsixMuAiEAh3LFabrEH6szI+UpBOguuw4DOZ6nZ00+q6Y7lGqFZZQ="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637802985.0_1637802987737_0.7890043915353253"},"_hasShrinkwrap":false},"2.0.1-next.1637803026.0":{"name":"@joist/component","version":"2.0.1-next.1637803026.0","main":"./target/build/lib.js","module":"./target/build/lib.js","exports":{".":{"import":"./target/build/lib.js"},"./observable":{"import":"./target/build/lib/observable.js"},"./styled":{"import":"./target/build/lib/styled.js"}},"sideEffects":false,"description":"Dependency Injection in ~800 bytes","repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"keywords":["TypeScript","DI","Dependency Injection"],"author":{"name":"deebloo"},"license":"MIT","bugs":{"url":"https://github.com/deebloo/joist/issues"},"publishConfig":{"access":"public"},"scripts":{"test":"tsc -p tsconfig.test.json && wtr --config ../../wtr.config.mjs --port 8000","build":"tsc -p tsconfig.build.json"},"gitHead":"6183a59777dab4652e1bbd13c08a614259cd2a56","readme":"# Di\n\nDependency Injection in ~800 bytes. Can be used with and without decorators.\n\n#### Installation:\n\n```BASH\nnpm i @joist/di\n```\n\n#### Example:\n\n```TS\nimport { Injector } from '@joist/di';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  static deps = [FooService];\n\n  constructor(private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\nconst app = new Injector();\n\napp.get(BarService).sayHello(); // Hello from BarService and Hello from FooService\n```\n\n#### Override A Service:\n\n```TS\nimport { Injector } from '@joist/di';\nimport { inject } from '@joist/di/decorators';\n\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n\nclass BarService {\n  constructor(@inject(FooService) private foo: FooService) {}\n\n  sayHello() {\n    return 'Hello From BarService and ' + this.foo.sayHello();\n  }\n}\n\n// Override FooService with an alternate implementation\nconst app = new Injector({\n  providers: [\n    {\n      provide: FooService,\n      use: class extends FooService {\n        sayHello() {\n          return 'IT HAS BEEN OVERRIDEN'\n        }\n      }\n    }\n  ]\n});\n\napp.get(BarService).sayHello(); // Hello from BarService and IT HAS BEEN OVERRIDEN\n```\n\n#### Root Service\n\nIf you have nested injectors and you still want singleton instances mark your service as shown or decorate with `@service()`\n\n```TS\nclass FooService {\n  static providedInRoot = true;\n\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n\n```TS\nimport { service } from '@joist/di/decorators';\n\n@service()\nclass FooService {\n  sayHello() {\n    return 'Hello From FooService';\n  }\n}\n```\n","readmeFilename":"README.md","homepage":"https://github.com/deebloo/joist#readme","_id":"@joist/component@2.0.1-next.1637803026.0","_nodeVersion":"14.18.1","_npmVersion":"lerna/4.0.0/node@v14.18.1+x64 (linux)","dist":{"integrity":"sha512-hF1B3ofKD7Hgg7RudHP1vMGBYWLJAVraVpohREzTVxdfhJdAGHoQ6bQ5WMeUtLV+cM+u5OSqSGTKN3Lowyy9Bw==","shasum":"6068f29edd0f18dbb959b32060cc6fd1e1e7439d","tarball":"https://registry.npmjs.org/@joist/component/-/component-2.0.1-next.1637803026.0.tgz","fileCount":14,"unpackedSize":50352,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJhnuQUCRA9TVsSAnZWagAAuFIP/3XScEWnnFcYe617IUFt\nH5ZrzfGwStWFCyDKTyOPRWz4n0mHMmp1qoTsadHqhBPHDL/OkIgU7fMmw2EL\nFgsGKsrH6QCHz1YdHamScsH69gDOPjSTvc9YQV00wdJDUmIGui5uB9VzvwOm\n5QckxHJi+2G7952uCTM4A5WhP6jghqXuLj+joWb4OCHbDS2MilrwaZWMYYn/\nLx3IzZdHp633uf9QPtufjLxuYwUyaCLMm8ghqYGuVbELiZISZmHqCn1QLDdK\nyjh4pS+nrfegQgEmJ72ClZ2BlBXDv+x4iOaH5AT3f/3HO29xiYbXfoG/Gm8P\n/n97Q7TjFfPvbOcfRJY6cC0hamK9P8gqsKqOli2On+FHxriLktlp8f8ER53h\nD4ygZqfvcXH4KmwPCFeDOjZVeiGLrEbcifbcyfkLa2c6SysL5y4wIQrTZ7kS\nzQij7Yt/c4rJGr3dfkZ/Ii8/m/V0LHxvuSsgFbP7viC3Zz9QbCPUlx1aKf8J\ng7Hy8Kqb4smsuVzWmqHE+8mLTxliUIzyaN5VN9n9ZNINUbAYZgg5QWw5Vd+Q\nNjyOigyZdDobF6BnTSCYZccu7P9kSb5paX6e0tIuXa5hsSrWYzkPis7Dzxu9\nCPpUeW5ILVJImItD+a7rccqC6zuegXNduiJxa9VecNJeN9pRg/KWZADchg0B\nCjN/\r\n=l3Ek\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCICz/+YcUzzWR6OkYHrQ5KLDpXkttgVN9MsnVVTyPr9i4AiEAsf4A4eYoGVJToPD/HqfsBq15mMk8KTGLEW0G7b5H84A="}]},"_npmUser":{"name":"deebloo","email":"dannybluedesign@gmail.com"},"directories":{},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/component_2.0.1-next.1637803026.0_1637803028471_0.504055537452657"},"_hasShrinkwrap":false}},"time":{"created":"2020-04-29T20:26:40.702Z","1.0.0-alpha.0":"2020-04-29T20:26:41.252Z","modified":"2022-04-05T22:14:14.342Z","1.0.0-alpha.1":"2020-04-29T21:30:11.298Z","1.0.0-alpha.2":"2020-04-29T21:37:56.436Z","1.0.0-alpha.3":"2020-05-01T02:17:43.975Z","1.0.0-alpha.4":"2020-05-01T11:48:18.059Z","1.0.0-alpha.5":"2020-05-02T14:42:45.737Z","1.0.0-alpha.6":"2020-05-02T23:31:39.255Z","1.0.0-alpha.7":"2020-05-03T00:05:18.833Z","1.0.0-alpha.8":"2020-05-03T01:09:56.528Z","1.0.0-alpha.9":"2020-05-03T04:44:15.965Z","1.0.0-alpha.10":"2020-05-09T15:18:17.075Z","1.0.0-alpha.11":"2020-05-09T15:20:27.664Z","1.0.0-alpha.12":"2020-05-09T15:22:45.247Z","1.0.0-alpha.13":"2020-05-09T15:35:06.176Z","1.0.0-alpha.14":"2020-05-09T16:58:49.617Z","1.0.0-alpha.15":"2020-05-22T20:59:00.167Z","1.0.0-alpha.16":"2020-05-23T04:15:38.572Z","1.0.0-alpha.17":"2020-05-27T14:53:15.641Z","1.0.0-alpha.19":"2020-07-22T16:29:52.659Z","1.0.0-alpha.20":"2020-07-23T14:59:03.893Z","1.0.0-alpha.21":"2020-07-24T12:49:59.351Z","1.0.0-alpha.22":"2020-07-24T15:31:35.664Z","1.0.0-alpha.23":"2020-07-24T18:01:00.953Z","1.0.0-alpha.24":"2020-07-24T21:19:30.184Z","1.0.0-alpha.25":"2020-07-25T00:45:18.156Z","1.0.0-alpha.27":"2020-07-26T13:31:41.259Z","1.0.0-alpha.28":"2020-07-26T13:40:14.428Z","1.0.0-alpha.29":"2020-07-27T13:52:56.181Z","1.0.0-alpha.30":"2020-07-27T19:27:38.297Z","1.0.0-beta.0":"2020-07-27T19:28:21.853Z","1.0.0-beta.1":"2020-07-27T19:39:52.546Z","1.0.0-beta.2":"2020-07-28T02:18:27.843Z","1.0.0-beta.3":"2020-07-28T15:14:09.455Z","1.0.0":"2020-07-28T16:09:35.818Z","1.0.1":"2020-07-31T21:27:08.390Z","1.0.2":"2020-08-01T00:37:16.253Z","1.0.3":"2020-08-01T01:15:20.623Z","1.0.4":"2020-08-03T02:17:31.944Z","1.0.5":"2020-08-03T02:49:00.814Z","1.0.6":"2020-08-03T18:57:24.467Z","1.0.7":"2020-08-05T17:24:08.495Z","1.0.8":"2020-08-05T18:45:17.034Z","1.0.9":"2020-08-05T21:25:13.029Z","1.1.0":"2020-08-06T16:22:13.326Z","1.1.1":"2020-08-07T17:25:17.917Z","1.1.2":"2020-08-07T17:31:34.040Z","1.1.3":"2020-08-07T17:53:02.673Z","1.1.4-next.0":"2020-08-08T18:19:04.951Z","1.1.4-alpha.0":"2020-08-08T18:25:45.658Z","1.1.4-be69752c5ccf7fe8e9488a79e07630e213ba1b3c.0":"2020-08-08T21:29:34.227Z","1.1.4-canary.1596923079.0":"2020-08-08T21:44:49.479Z","1.1.4-canary.1597006052.0":"2020-08-09T20:47:41.863Z","1.1.4-canary.1597006752.0":"2020-08-09T20:59:21.759Z","1.1.4-canary.1597007297.0":"2020-08-09T21:08:27.561Z","1.2.1-canary.1597007506.0":"2020-08-09T21:11:55.645Z","1.2.1":"2020-08-09T21:12:05.698Z","1.2.2-canary.1597007558.0":"2020-08-09T21:12:47.163Z","1.2.2-canary.1597016555.0":"2020-08-09T23:42:43.879Z","1.2.2-canary.1597017672.0":"2020-08-10T00:01:21.817Z","1.2.2-canary.0":"2020-08-10T03:41:58.504Z","1.2.2-canary.1597031190.0":"2020-08-10T03:46:37.749Z","1.2.2-canary.1597065868.0":"2020-08-10T13:24:36.316Z","1.2.2-canary.1597065930.0":"2020-08-10T13:25:44.739Z","1.2.2-canary.1597153164.0":"2020-08-11T13:39:33.604Z","1.2.2-canary.1597157533.0":"2020-08-11T14:52:21.255Z","1.2.2-canary.1597158866.0":"2020-08-11T15:14:35.466Z","1.2.2-canary.1597158927.0":"2020-08-11T15:15:38.050Z","1.2.2-canary.1597158982.0":"2020-08-11T15:16:32.587Z","1.2.2-canary.1597159017.0":"2020-08-11T15:17:07.341Z","1.2.2-canary.1597159271.0":"2020-08-11T15:21:21.013Z","1.2.2-canary.1597162545.0":"2020-08-11T16:15:56.279Z","1.2.2-canary.1597170842.0":"2020-08-11T18:34:12.147Z","1.2.2-canary.1597171698.0":"2020-08-11T18:48:27.012Z","1.2.2-canary.1597173679.0":"2020-08-11T19:21:29.297Z","1.2.2-canary.1597174225.0":"2020-08-11T19:30:35.046Z","1.2.2-canary.1597176000.0":"2020-08-11T20:00:10.384Z","1.2.2-canary.1597176081.0":"2020-08-11T20:01:32.076Z","1.2.2-canary.1597176297.0":"2020-08-11T20:05:08.665Z","1.2.2-canary.1597176632.0":"2020-08-11T20:10:41.702Z","1.2.2-canary.1597178849.0":"2020-08-11T20:47:40.814Z","1.2.2-canary.1597236972.0":"2020-08-12T12:56:21.955Z","1.3.0":"2020-08-12T12:57:45.668Z","1.3.1-canary.1597237092.0":"2020-08-12T12:58:22.840Z","1.3.1-canary.1597237988.0":"2020-08-12T13:13:17.538Z","1.3.1-canary.1597239751.0":"2020-08-12T13:42:40.980Z","1.3.1-canary.1597240853.0":"2020-08-12T14:01:03.333Z","1.3.1-canary.1597244062.0":"2020-08-12T14:54:31.419Z","1.3.1-canary.1597246153.0":"2020-08-12T15:29:22.881Z","1.3.1-canary.1597246631.0":"2020-08-12T15:37:20.142Z","1.3.1-canary.1597262701.0":"2020-08-12T20:05:10.150Z","1.3.1-canary.1597263673.0":"2020-08-12T20:21:22.557Z","1.3.1-canary.1597290629.0":"2020-08-13T03:50:40.381Z","1.3.1-canary.1597290988.0":"2020-08-13T03:56:38.595Z","1.3.1-canary.1597291029.0":"2020-08-13T03:57:18.749Z","1.3.1-canary.1597320809.0":"2020-08-13T12:13:40.064Z","1.3.1-canary.1597328123.0":"2020-08-13T14:15:33.318Z","1.3.1-canary.1597328327.0":"2020-08-13T14:19:05.380Z","1.3.1-canary.1597333919.0":"2020-08-13T15:52:08.264Z","1.3.1-canary.1597349545.0":"2020-08-13T20:12:35.896Z","1.3.1-canary.1597374778.0":"2020-08-14T03:13:08.395Z","1.3.1-canary.1597408744.0":"2020-08-14T12:39:23.263Z","1.3.1-canary.1597413165.0":"2020-08-14T13:53:06.041Z","1.3.1-canary.1597431329.0":"2020-08-14T18:55:39.942Z","1.3.1-canary.1597500141.0":"2020-08-15T14:02:31.541Z","1.3.1-canary.1597578829.0":"2020-08-16T11:53:58.805Z","1.3.1-canary.1597578870.0":"2020-08-16T11:54:39.632Z","1.3.1-canary.1597606352.0":"2020-08-16T19:32:40.773Z","1.3.1-canary.1597609080.0":"2020-08-16T20:18:10.149Z","1.3.1-canary.1597711149.0":"2020-08-18T00:39:19.227Z","1.3.1-canary.1597838191.0":"2020-08-19T11:56:39.763Z","1.3.1-canary.1597840643.0":"2020-08-19T12:37:33.395Z","1.3.1-canary.1597880798.0":"2020-08-19T23:46:47.034Z","1.3.1-canary.1597881741.0":"2020-08-20T00:02:29.606Z","1.3.1-canary.1597881860.0":"2020-08-20T00:04:30.304Z","1.3.1-canary.1597881958.0":"2020-08-20T00:06:08.509Z","1.3.1-canary.1597882151.0":"2020-08-20T00:09:19.827Z","1.4.0":"2020-08-20T00:11:45.298Z","1.4.1-canary.1597882339.0":"2020-08-20T00:12:29.648Z","1.4.1-canary.1597882712.0":"2020-08-20T00:18:42.019Z","1.4.1-canary.1597882871.0":"2020-08-20T00:21:21.751Z","1.4.1-canary.1597883869.0":"2020-08-20T00:38:00.153Z","1.4.1-canary.1597884130.0":"2020-08-20T00:42:20.107Z","1.4.1-canary.1597925879.0":"2020-08-20T12:18:08.860Z","1.4.1-canary.1597933312.0":"2020-08-20T14:22:03.428Z","1.4.1-canary.1597940949.0":"2020-08-20T16:29:19.157Z","1.4.1-canary.1597941184.0":"2020-08-20T16:33:14.708Z","1.4.1-canary.1597952988.0":"2020-08-20T19:49:56.489Z","1.4.1-canary.1597957225.0":"2020-08-20T21:00:35.871Z","1.4.1-canary.1597959273.0":"2020-08-20T21:34:42.797Z","1.4.1-canary.1597961951.0":"2020-08-20T22:19:21.099Z","1.4.1-canary.1598023384.0":"2020-08-21T15:23:12.684Z","1.4.1-canary.1598040868.0":"2020-08-21T20:14:37.796Z","1.4.1-canary.1598041497.0":"2020-08-21T20:25:07.422Z","1.4.1-canary.1598041565.0":"2020-08-21T20:26:14.559Z","1.4.1-canary.1598105375.0":"2020-08-22T14:09:45.763Z","1.4.1-canary.1598105395.0":"2020-08-22T14:10:04.219Z","1.4.1-canary.1598155326.0":"2020-08-23T04:02:15.812Z","1.5.0":"2020-08-24T01:13:01.367Z","1.5.1-canary.1598231619.0":"2020-08-24T01:13:49.031Z","1.5.1-canary.1598231857.0":"2020-08-24T01:17:45.678Z","1.5.1-canary.1598232026.0":"2020-08-24T01:20:34.278Z","1.5.1-canary.1598269988.0":"2020-08-24T11:53:18.039Z","1.5.1-canary.1598357339.0":"2020-08-25T12:09:09.435Z","1.5.1-canary.1598357359.0":"2020-08-25T12:09:28.292Z","1.5.1-canary.1598369528.0":"2020-08-25T15:32:18.087Z","1.5.1-canary.1598371506.0":"2020-08-25T16:05:15.699Z","1.5.1-canary.1598372767.0":"2020-08-25T16:26:17.249Z","1.5.1-canary.1598380441.0":"2020-08-25T18:34:15.430Z","1.5.1-canary.1598442548.0":"2020-08-26T11:49:20.871Z","1.5.1-canary.1598442904.0":"2020-08-26T11:55:13.812Z","1.5.1-canary.1598447580.0":"2020-08-26T13:13:10.442Z","1.5.1-canary.1598527037.0":"2020-08-27T11:17:25.632Z","1.5.1-canary.1598527094.0":"2020-08-27T11:18:24.160Z","1.5.1-canary.1598527157.0":"2020-08-27T11:19:24.840Z","1.5.1-canary.1598530503.0":"2020-08-27T12:15:19.531Z","1.5.1-canary.1598546041.0":"2020-08-27T16:34:11.058Z","1.5.1-canary.1598620401.0":"2020-08-28T13:13:31.652Z","1.5.1-canary.1598628434.0":"2020-08-28T15:27:24.798Z","1.5.1-canary.1598629471.0":"2020-08-28T15:44:40.903Z","1.6.0":"2020-08-28T16:05:36.400Z","1.6.1-canary.1598630769.0":"2020-08-28T16:06:20.535Z","1.6.1-canary.1598636182.0":"2020-08-28T17:36:31.600Z","1.6.1-canary.1598636291.0":"2020-08-28T17:38:20.648Z","1.6.1-canary.1598636394.0":"2020-08-28T17:40:04.100Z","1.6.1-canary.1598700250.0":"2020-08-29T11:24:20.263Z","1.6.1-canary.1598734916.0":"2020-08-29T21:02:07.183Z","1.6.1-canary.1598735539.0":"2020-08-29T21:12:27.552Z","1.6.1-canary.1598744040.0":"2020-08-29T23:34:09.721Z","1.6.1-canary.1598794783.0":"2020-08-30T13:39:53.070Z","1.6.1-canary.1598798708.0":"2020-08-30T14:45:18.735Z","1.6.1-canary.1598900228.0":"2020-08-31T18:57:17.991Z","1.6.1-canary.1598904195.0":"2020-08-31T20:03:24.279Z","1.6.1-canary.1598920916.0":"2020-09-01T00:42:06.121Z","1.6.1-canary.1598960325.0":"2020-09-01T11:38:56.694Z","1.6.1-canary.1598971652.0":"2020-09-01T14:47:42.291Z","1.6.1-canary.1598971688.0":"2020-09-01T14:48:17.977Z","1.6.1-canary.1598977763.0":"2020-09-01T16:29:33.535Z","1.6.1-canary.1598987107.0":"2020-09-01T19:05:17.553Z","1.6.1-canary.1598998346.0":"2020-09-01T22:12:35.407Z","1.6.1-canary.1598998587.0":"2020-09-01T22:16:36.705Z","1.6.1-canary.1599063095.0":"2020-09-02T16:11:45.692Z","1.6.1-canary.1599063965.0":"2020-09-02T16:26:15.073Z","1.6.1-canary.1599076498.0":"2020-09-02T19:55:08.352Z","1.6.1-canary.1599129722.0":"2020-09-03T10:42:10.259Z","1.6.1-canary.1599139368.0":"2020-09-03T13:22:58.167Z","1.6.1-canary.1599164947.0":"2020-09-03T20:29:16.691Z","1.6.1-canary.1599224463.0":"2020-09-04T13:01:13.473Z","1.6.1-canary.1599257919.0":"2020-09-04T22:18:48.559Z","1.6.1-canary.1599418898.0":"2020-09-06T19:01:48.182Z","1.6.1-canary.1599477682.0":"2020-09-07T11:21:31.668Z","1.6.1-canary.1599569957.0":"2020-09-08T12:59:25.974Z","1.6.1-canary.1599569997.0":"2020-09-08T13:00:07.340Z","1.6.1-canary.1599570015.0":"2020-09-08T13:00:25.105Z","1.6.1-canary.1599592429.0":"2020-09-08T19:13:58.682Z","1.6.1-canary.1599592446.0":"2020-09-08T19:14:15.908Z","1.6.1-canary.1599595014.0":"2020-09-08T19:57:02.883Z","1.6.1-canary.1599607914.0":"2020-09-08T23:32:03.867Z","1.6.1-canary.1599670545.0":"2020-09-09T16:55:54.963Z","1.6.1-canary.1599849338.0":"2020-09-11T18:35:48.917Z","1.6.1-canary.1599915801.0":"2020-09-12T13:03:29.623Z","1.6.1-canary.1599915979.0":"2020-09-12T13:06:29.934Z","1.6.1-canary.1599997736.0":"2020-09-13T11:49:06.401Z","1.6.1-canary.1600221675.0":"2020-09-16T02:01:25.207Z","1.6.1-canary.1600258096.0":"2020-09-16T12:08:25.727Z","1.6.1-canary.1600263267.0":"2020-09-16T13:34:36.544Z","1.6.1-canary.1600268818.0":"2020-09-16T15:07:06.891Z","1.6.1-canary.1600293365.0":"2020-09-16T21:56:15.493Z","1.6.1-canary.1600344903.0":"2020-09-17T12:15:18.284Z","1.6.1-canary.1600460240.0":"2020-09-18T20:17:30.452Z","1.6.1-canary.1600515410.0":"2020-09-19T11:37:00.082Z","1.6.1-canary.1600520883.0":"2020-09-19T13:08:12.903Z","1.6.1-canary.1600691675.0":"2020-09-21T12:34:45.589Z","1.6.1-canary.1600967979.0":"2020-09-24T17:19:48.739Z","1.6.1-canary.1601064146.0":"2020-09-25T20:02:36.389Z","1.6.1-canary.1601064148.0":"2020-09-25T20:02:52.717Z","1.6.1-canary.1601070741.0":"2020-09-25T21:52:31.744Z","1.6.1-canary.1601155745.0":"2020-09-26T21:29:16.399Z","1.6.1-canary.1601215868.0":"2020-09-27T14:11:16.940Z","1.6.1-canary.1601349632.0":"2020-09-29T03:20:41.537Z","1.6.1-canary.1601409860.0":"2020-09-29T20:04:30.649Z","1.6.1-canary.1601424284.0":"2020-09-30T00:04:54.753Z","1.6.1-canary.1601424292.0":"2020-09-30T00:05:02.394Z","1.6.1-canary.1601497934.0":"2020-09-30T20:32:25.092Z","1.6.1-canary.1601514866.0":"2020-10-01T01:14:36.850Z","1.6.1-canary.1601576242.0":"2020-10-01T18:17:31.496Z","1.6.1-canary.1601680608.0":"2020-10-02T23:16:59.051Z","1.6.1-canary.1601726027.0":"2020-10-03T11:53:56.531Z","1.6.1-canary.1601756060.0":"2020-10-03T20:14:30.039Z","1.6.1-canary.1601908406.0":"2020-10-05T14:33:35.939Z","1.6.1-canary.1601908665.0":"2020-10-05T14:37:55.924Z","1.6.1-canary.1601908965.0":"2020-10-05T14:42:54.235Z","1.6.1-canary.1601909298.0":"2020-10-05T14:48:27.788Z","1.6.1-canary.1601919412.0":"2020-10-05T17:37:02.344Z","1.6.1-canary.1601952646.0":"2020-10-06T02:50:57.272Z","1.6.1-canary.1601991516.0":"2020-10-06T13:38:46.045Z","1.6.1-canary.1602000049.0":"2020-10-06T16:00:59.775Z","1.6.1-canary.1602012693.0":"2020-10-06T19:31:48.538Z","1.6.1-canary.1602108254.0":"2020-10-07T22:04:24.322Z","1.6.1-canary.1602158955.0":"2020-10-08T12:09:24.766Z","1.6.1-canary.1602159004.0":"2020-10-08T12:10:14.640Z","1.6.1-canary.1602249164.0":"2020-10-09T13:12:54.422Z","1.6.1-canary.1602298659.0":"2020-10-10T02:57:48.080Z","1.6.1-canary.1602469909.0":"2020-10-12T02:31:59.553Z","1.6.1-canary.1602508143.0":"2020-10-12T13:09:12.989Z","1.6.1-canary.1602508139.0":"2020-10-12T13:09:28.259Z","1.6.1-canary.1602533512.0":"2020-10-12T20:12:02.816Z","1.6.1-canary.1602623357.0":"2020-10-13T21:09:26.820Z","1.6.1-canary.1602697281.0":"2020-10-14T17:41:30.822Z","1.6.1-canary.1602698012.0":"2020-10-14T17:53:42.150Z","1.6.1-canary.1602716535.0":"2020-10-14T23:02:25.401Z","1.6.1-canary.1602790518.0":"2020-10-15T19:35:28.173Z","1.6.1-canary.1602796781.0":"2020-10-15T21:19:54.594Z","1.6.1-canary.1602853627.0":"2020-10-16T13:07:17.243Z","1.6.1-canary.1602853637.0":"2020-10-16T13:07:27.483Z","1.6.1-canary.1602854443.0":"2020-10-16T13:20:52.106Z","1.6.1-canary.1602863775.0":"2020-10-16T15:56:24.170Z","1.6.1-canary.1602867626.0":"2020-10-16T17:00:35.471Z","1.6.1-canary.1602872896.0":"2020-10-16T18:28:26.611Z","1.6.1-canary.1602881103.0":"2020-10-16T20:45:14.067Z","1.6.1-canary.1602897667.0":"2020-10-17T01:21:17.028Z","1.6.1-canary.1602961139.0":"2020-10-17T18:59:07.273Z","1.6.1-canary.1603122206.0":"2020-10-19T15:43:36.093Z","1.6.1-canary.1603200914.0":"2020-10-20T13:35:24.168Z","1.6.1-canary.1605118601.0":"2020-11-11T18:16:51.574Z","1.6.1-canary.1606235949.0":"2020-11-24T16:39:18.416Z","1.6.1-canary.1606242401.0":"2020-11-24T18:26:52.136Z","1.7.0":"2020-11-24T18:29:24.536Z","1.7.1-canary.1606242654.0":"2020-11-24T18:31:02.243Z","1.7.1-canary.1606271510.0":"2020-11-25T02:31:59.517Z","1.7.1-canary.1607527688.0":"2020-12-09T15:28:19.274Z","1.7.1-canary.1611081429.0":"2021-01-19T18:37:19.808Z","1.7.1-canary.1615491241.0":"2021-03-11T19:34:10.724Z","1.7.1-canary.1618631004.0":"2021-04-17T03:43:33.293Z","1.7.1-canary.1618783411.0":"2021-04-18T22:03:42.114Z","1.7.1-canary.1619551582.0":"2021-04-27T19:26:33.477Z","1.8.1":"2021-04-27T19:28:59.182Z","1.7.1-canary.1619551753.0":"2021-04-27T19:29:24.405Z","1.7.1-canary.1619551780.0":"2021-04-27T19:29:51.186Z","1.8.0":"2021-04-27T19:30:41.004Z","1.8.2":"2021-04-27T19:31:13.176Z","1.8.1-canary.1619551931.0":"2021-04-27T19:32:22.212Z","1.8.3-canary.1619551982.0":"2021-04-27T19:33:14.572Z","1.8.3-canary.1619554665.0":"2021-04-27T20:17:58.641Z","1.8.3":"2021-04-27T20:18:36.054Z","1.8.4-canary.1619554801.0":"2021-04-27T20:20:12.206Z","1.8.4-canary.1619555984.0":"2021-04-27T20:39:56.572Z","1.8.4-canary.1619555999.0":"2021-04-27T20:40:09.722Z","1.8.4-canary.1619556102.0":"2021-04-27T20:41:52.866Z","1.8.4-canary.1619556550.0":"2021-04-27T20:49:20.234Z","1.8.4-canary.1619556662.0":"2021-04-27T20:51:14.092Z","1.8.4":"2021-04-28T20:25:41.485Z","1.8.5-canary.1619641637.0":"2021-04-28T20:27:27.986Z","1.8.5-canary.1619708354.0":"2021-04-29T14:59:23.423Z","1.8.5-canary.1620101283.0":"2021-05-04T04:08:14.121Z","1.8.5-canary.1620138949.0":"2021-05-04T14:35:58.173Z","1.8.5":"2021-05-04T15:10:42.757Z","1.8.6-canary.1620141152.0":"2021-05-04T15:12:42.786Z","1.8.6-canary.1621387626.0":"2021-05-19T01:27:18.689Z","1.8.6":"2021-05-19T01:28:02.005Z","1.8.7-canary.1621387788.0":"2021-05-19T01:29:58.966Z","1.8.7-canary.1622044874.0":"2021-05-26T16:01:24.830Z","1.8.7-canary.1622817902.0":"2021-06-04T14:45:12.415Z","1.8.7-canary.1626922834.0":"2021-07-22T03:00:36.893Z","1.8.7-canary.1626923316.0":"2021-07-22T03:08:38.388Z","1.8.7-canary.1627917432.0":"2021-08-02T15:17:14.693Z","1.8.7-canary.1630520794.0":"2021-09-01T18:26:37.169Z","1.8.7":"2021-10-29T14:55:23.653Z","1.8.8":"2021-10-29T15:00:50.801Z","1.8.9-canary.1637250860.0":"2021-11-18T15:54:23.567Z","1.8.9":"2021-11-18T15:55:46.976Z","1.8.10":"2021-11-18T15:56:15.229Z","1.8.11-canary.1637251084.0":"2021-11-18T15:58:06.880Z","2.0.1-next.1637555722.0":"2021-11-22T04:35:25.168Z","2.0.1-next.1637557002.0":"2021-11-22T04:56:44.589Z","2.0.1-next.1637557415.0":"2021-11-22T05:03:37.628Z","2.0.1-next.1637557736.0":"2021-11-22T05:08:59.439Z","2.0.1-next.1637558322.0":"2021-11-22T05:18:45.300Z","2.0.1-next.1637558585.0":"2021-11-22T05:23:08.075Z","2.0.1-next.1637558883.0":"2021-11-22T05:28:05.208Z","2.0.1-next.1637592115.0":"2021-11-22T14:41:57.384Z","2.0.1-next.1637615403.0":"2021-11-22T21:10:06.288Z","2.0.1-next.1637615494.0":"2021-11-22T21:11:37.249Z","2.0.1-next.1637615741.0":"2021-11-22T21:15:43.974Z","2.0.1-next.1637616487.0":"2021-11-22T21:28:10.336Z","2.0.1-next.1637619197.0":"2021-11-22T22:13:19.819Z","2.0.1-next.1637678584.0":"2021-11-23T14:43:06.563Z","2.0.1-next.1637679117.0":"2021-11-23T14:51:59.541Z","2.0.1-next.1637679901.0":"2021-11-23T15:05:04.048Z","2.0.1-next.1637684016.0":"2021-11-23T16:13:38.862Z","2.0.1-next.1637688688.0":"2021-11-23T17:31:30.729Z","2.0.1-next.1637688999.0":"2021-11-23T17:36:41.943Z","2.0.1-next.1637728152.0":"2021-11-24T04:29:15.877Z","2.0.1-next.1637773272.0":"2021-11-24T17:01:14.395Z","2.0.1-next.1637776053.0":"2021-11-24T17:47:36.293Z","2.0.1-next.1637783959.0":"2021-11-24T19:59:21.763Z","2.0.1-next.1637791325.0":"2021-11-24T22:02:07.911Z","2.0.1-next.1637802060.0":"2021-11-25T01:01:02.926Z","2.0.1-next.1637802130.0":"2021-11-25T01:02:12.935Z","2.0.1-next.1637802244.0":"2021-11-25T01:04:06.605Z","2.0.1-next.1637802271.0":"2021-11-25T01:04:33.716Z","2.0.1-next.1637802201.0":"2021-11-25T01:04:58.987Z","2.0.1-next.1637802368.0":"2021-11-25T01:06:10.269Z","2.0.1-next.1637802874.0":"2021-11-25T01:14:36.580Z","2.0.1-next.1637802923.0":"2021-11-25T01:15:25.543Z","2.0.1-next.1637802985.0":"2021-11-25T01:16:27.919Z","2.0.1-next.1637803026.0":"2021-11-25T01:17:08.646Z"},"maintainers":[{"name":"deebloo","email":"dannybluedesign@gmail.com"}],"description":"A framework for building web components, and applications with web components.","homepage":"https://github.com/deebloo/joist#readme","keywords":["lit-html","Web Components","Custom Elements","Shadow DOM"],"repository":{"type":"git","url":"git+https://github.com/deebloo/joist.git"},"author":{"name":"deebloo"},"bugs":{"url":"https://github.com/deebloo/joist/issues"},"license":"MIT","readme":"","readmeFilename":""}