Hello Lit!
`); 6 | document.body.appendChild(component) 7 | await component.updateComplete 8 | expect(component.shadowRoot?.textContent).toContain("Hello Lit!") 9 | }) -------------------------------------------------------------------------------- /.github/workflows/run-test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | test: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 13 | - uses: actions/checkout@v2 14 | 15 | - name: Setup Node.js environment 16 | uses: actions/setup-node@v2 17 | 18 | - name: Setup npm 19 | run: | 20 | npm install 21 | 22 | - name: Build the project 23 | run: npm run build 24 | 25 | - name: Test the project 26 | run: npm test 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "es2015", 5 | "lib": ["es2017", "dom", "dom.iterable"], 6 | "outDir": "./dist", 7 | "declaration": true, 8 | "declarationMap": true, 9 | "sourceMap": true, 10 | "strict": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true, 13 | "noImplicitReturns": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "moduleResolution": "node", 16 | "allowSyntheticDefaultImports": true, 17 | "experimentalDecorators": true, 18 | "forceConsistentCasingInFileNames": true, 19 | }, 20 | "include": ["**/*.ts"], 21 | "exclude": ["docs/", "dist/"] 22 | } 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Matthias Kainer 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /.github/workflows/dependabot.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-approve 2 | on: pull_request 3 | 4 | permissions: 5 | contents: write 6 | pull-requests: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' }} 12 | steps: 13 | - name: Dependabot metadata 14 | id: metadata 15 | uses: dependabot/fetch-metadata@v1.1.1 16 | with: 17 | github-token: "${{ secrets.GITHUB_TOKEN }}" 18 | - name: Approve a PR 19 | run: gh pr review --approve "$PR_URL" 20 | env: 21 | PR_URL: ${{github.event.pull_request.html_url}} 22 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 23 | - name: Enable auto-merge for Dependabot PRs 24 | run: gh pr merge --auto --merge "$PR_URL" 25 | env: 26 | PR_URL: ${{github.event.pull_request.html_url}} 27 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 28 | -------------------------------------------------------------------------------- /src/dispatch.test.ts: -------------------------------------------------------------------------------- 1 | import {dispatch} from "." 2 | 3 | describe("on", () => { 4 | const mock = jest.fn() 5 | const mockElement = { 6 | dispatchEvent: (e: CustomEvent) => mock(e.type, e.detail, e.bubbles) 7 | } 8 | beforeEach(() => { 9 | jest.resetAllMocks() 10 | }) 11 | 12 | it("adds the event dispatcher to the element with no data and bubbling", () => { 13 | dispatch(mockElement, "custom"); 14 | expect(mock).toBeCalledWith("custom", null, false) 15 | }) 16 | 17 | it("adds the event dispatcher and data if passed", () => { 18 | dispatch(mockElement, "custom", "data"); 19 | expect(mock).toBeCalledWith("custom", "data", false) 20 | }) 21 | it("adds the event dispatcher, data and options if passed", () => { 22 | dispatch(mockElement, "custom", "data", { bubbles: true }); 23 | expect(mock).toBeCalledWith("custom", "data", true) 24 | }) 25 | }) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /docs/badges/badge-lines.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/badges/badge-branches.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/badges/badge-functions.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/badges/badge-statements.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |Hello ${el.who}${el.whoElse}!
`, 11 | { 12 | styles: [css`:host {}`], 13 | props: [ {"who": {type: String} }, {"whoElse": {type: String}} ] 14 | }); 15 | document.body.appendChild(component) 16 | }) 17 | 18 | afterEach(() => { 19 | document.body.removeChild(component) 20 | }) 21 | 22 | 23 | it("renders the empty defaults", async () => { 24 | await component.updateComplete 25 | expect(component.shadowRoot?.textContent).toContain("Hello !") 26 | }); 27 | it("renders updated props correctlty", async () => { 28 | component.setAttribute("who", "John") 29 | await component.updateComplete 30 | expect(component.shadowRoot?.textContent).toContain("Hello John!"); 31 | }); 32 | it("renders updated dashed props correctlty", async () => { 33 | component.setAttribute("who", "John") 34 | component.setAttribute("who-else", "Wayne") 35 | await component.updateComplete 36 | expect(component.shadowRoot?.textContent).toContain("Hello JohnWayne!"); 37 | }); 38 | }) -------------------------------------------------------------------------------- /src/pure-lit.props-defaults.test.ts: -------------------------------------------------------------------------------- 1 | import { pureLit } from "./pure-lit"; 2 | import { html, css } from "lit"; 3 | import { LitElementWithProps } from "./types"; 4 | 5 | describe("pure-lit with prop by default specs", () => { 6 | type Props = { who: string, whoElse: string } 7 | let component: LitElementWithPropsHello ${el.who}${el.whoElse}!
`, 11 | { 12 | styles: [css`:host {}`], 13 | defaults: { 14 | who: "", 15 | whoElse: "" 16 | } 17 | }); 18 | document.body.appendChild(component) 19 | }) 20 | 21 | afterEach(() => { 22 | document.body.removeChild(component) 23 | }) 24 | 25 | 26 | it("renders the empty defaults", async () => { 27 | await component.updateComplete 28 | expect(component.shadowRoot?.textContent).toContain("Hello !") 29 | }); 30 | it("renders updated props correctlty", async () => { 31 | component.setAttribute("who", "John") 32 | await component.updateComplete 33 | expect(component.shadowRoot?.textContent).toContain("Hello John!"); 34 | }); 35 | it("renders updated dashed props correctlty", async () => { 36 | component.setAttribute("who", "John") 37 | component.setAttribute("who-else", "Wayne") 38 | await component.updateComplete 39 | expect(component.shadowRoot?.textContent).toContain("Hello JohnWayne!"); 40 | }); 41 | }) -------------------------------------------------------------------------------- /docs/_coverpage.md: -------------------------------------------------------------------------------- 1 | # pure-lit 2 | 3 | [](https://www.npmjs.com/package/pure-lit) 4 | [](https://bundlephobia.com/result?p=pure-lit) 5 | [](https://snyk.io/test/github/MatthiasKainer/pure-lit?targetFile=package.json) 6 | [](https://bundlephobia.com/result?p=pure-lit)Something went wrong. Please try again later.
41 |Hello ${el.who}!
`) 24 | ) 25 | ), 26 | { 27 | defaults: { who: "noone" }, 28 | suspense: html`wait while loading...` 29 | }); 30 | document.body.appendChild(component) 31 | await component.updateComplete 32 | }) 33 | 34 | afterEach(() => { 35 | document.body.removeChild(component) 36 | jest.resetAllMocks() 37 | }) 38 | 39 | it("renders the error correctly", async () => { 40 | component.setAttribute("who", "John") 41 | await component.updateComplete 42 | fail("omg omg we all gonna die") 43 | // suspense is slighty more async then your regular component 44 | await component.updateComplete 45 | await new Promise(process.nextTick) 46 | expect(component.shadowRoot?.textContent).toContain("omg omg we all gonna die") 47 | }); 48 | 49 | }); -------------------------------------------------------------------------------- /src/pure-lit.boolean-attrs.test.ts: -------------------------------------------------------------------------------- 1 | import { pureLit, LitElementWithProps } from "."; 2 | import { html, css } from "lit"; 3 | import {screen} from 'testing-library__dom'; 4 | 5 | type Props = { val: boolean, string: string }; 6 | 7 | const testComponent = pureLit( 8 | "my-component", 9 | (el: LitElementWithPropsVal is ${el.val} ${el.string}!
`, 10 | { 11 | styles: [ 12 | css` 13 | :host { 14 | } 15 | `, 16 | ], 17 | defaults: { val: false, string: "bla" } 18 | } 19 | ); 20 | 21 | describe("pure-lit boolean attributes default", () => { 22 | beforeEach(async () => { 23 | document.body.appendChild(testComponent); 24 | }); 25 | 26 | afterEach(() => { 27 | document.body.removeChild(testComponent); 28 | }); 29 | 30 | it("should have the correct default value", () => { 31 | expect(screen.getByText(/Val is false/gi)).toBeDefined() 32 | }) 33 | 34 | it("should update the attribute if it changes", async () => { 35 | testComponent.val = true 36 | await testComponent.updateComplete 37 | expect(screen.getByText(/Val is true/gi)).toBeDefined() 38 | }) 39 | }); 40 | 41 | describe("pure-lit boolean attributes set explicitly", () => { 42 | beforeEach(async () => { 43 | document.body.insertAdjacentHTML( 'beforeend', "Hello ${el.who}!
`)) 27 | ) 28 | }), 29 | { 30 | defaults: { who: "noone" }, 31 | suspense: html`wait while loading...` 32 | }); 33 | document.body.appendChild(component) 34 | await component.updateComplete 35 | }) 36 | 37 | afterEach(() => { 38 | global.window.document.documentElement.innerHTML = ""; 39 | }) 40 | 41 | it("renders updated props correctly for suspense", async () => { 42 | await releaseSuspense() 43 | await component.suspenseComplete(); 44 | expect(component.shadowRoot?.textContent).toContain("Hello noone!") 45 | 46 | component.setAttribute("who", "John") 47 | await releaseSuspense() 48 | await component.suspenseComplete(); 49 | expect(component.shadowRoot?.textContent).toContain("Hello John!"); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from "rollup-plugin-terser"; 2 | import resolve from "@rollup/plugin-node-resolve"; 3 | import replace from "@rollup/plugin-replace"; 4 | import commonjs from "@rollup/plugin-commonjs"; 5 | import json from "@rollup/plugin-json"; 6 | import typescript from "rollup-plugin-typescript2"; 7 | import filesize from "rollup-plugin-filesize"; 8 | import minifyHTML from "rollup-plugin-minify-html-literals"; 9 | 10 | import pkg from "./package.json"; 11 | 12 | const input = `./src/index.ts`; 13 | const plugins = [ 14 | typescript(), 15 | replace({ "Reflect.decorate": "undefined" }), 16 | minifyHTML(), 17 | commonjs(), 18 | resolve(), 19 | json(), 20 | terser({ 21 | module: true, 22 | warnings: true, 23 | mangle: { 24 | properties: { 25 | regex: /^__/, 26 | }, 27 | }, 28 | }), 29 | filesize({ 30 | showBrotliSize: true, 31 | }), 32 | ]; 33 | const external = ["lit"] 34 | 35 | const get = (input, pkg) => { 36 | const mainBundle = { 37 | input, 38 | external, 39 | output: { 40 | file: pkg.module, 41 | format: "esm", 42 | sourcemap: true, 43 | }, 44 | plugins, 45 | }; 46 | 47 | const cjsBundle = { 48 | input, 49 | external, 50 | output: { 51 | file: pkg.main, 52 | format: "cjs", 53 | sourcemap: true, 54 | }, 55 | plugins, 56 | }; 57 | 58 | const systemBundle = { 59 | input, 60 | external, 61 | output: { 62 | file: pkg.system, 63 | format: "system", 64 | sourcemap: true, 65 | }, 66 | plugins, 67 | }; 68 | return [mainBundle, cjsBundle, systemBundle] 69 | } 70 | 71 | export default [ 72 | ...get(input, pkg) 73 | ]; 74 | -------------------------------------------------------------------------------- /src/pure-lit.suspense.part3.test.ts: -------------------------------------------------------------------------------- 1 | import { pureLit } from "./pure-lit"; 2 | import { html } from "lit"; 3 | import { LitElementWithProps } from "./types"; 4 | 5 | // jest doesn't run tests in the same file in isolation, 6 | // which has led to sideeffects and bugs. Splitting this up 7 | 8 | describe("pure-lit suspense happy case", () => { 9 | type Props = { who: string } 10 | let component: LitElementWithPropsHello ${el.who}!
`)) 27 | ) 28 | }), 29 | { 30 | defaults: { who: "noone" }, 31 | suspense: html`wait while loading...` 32 | }); 33 | document.body.appendChild(component) 34 | await component.updateComplete 35 | }) 36 | 37 | afterEach(() => { 38 | global.window.document.documentElement.innerHTML = ""; 39 | }) 40 | 41 | 42 | it("reinitializes correctly", async () => { 43 | await releaseSuspense() 44 | await component.suspenseComplete(); 45 | expect(component.shadowRoot?.textContent).toContain("Hello noone!") 46 | 47 | component.setAttribute("who", "John") 48 | await Promise.all([ 49 | component.suspenseComplete(), 50 | releaseSuspense(), 51 | ]); 52 | expect(component.shadowRoot?.textContent).toContain("Hello John!"); 53 | 54 | component.reinitialize() 55 | await Promise.all([ 56 | component.suspenseComplete(), 57 | releaseSuspense(), 58 | ]); 59 | expect(component.shadowRoot?.textContent).toContain("Hello noone!") 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/pure-lit.suspense.part1.test.ts: -------------------------------------------------------------------------------- 1 | import { registered, pureLit } from "./pure-lit"; 2 | import { html } from "lit"; 3 | import { LitElementWithProps } from "./types"; 4 | 5 | describe("pure-lit suspense happy case", () => { 6 | type Props = { who: string } 7 | let component: LitElementWithPropsHello ${el.who}!
`)) 24 | ) 25 | }), 26 | { 27 | defaults: { who: "noone" }, 28 | suspense: html`wait while loading...` 29 | }); 30 | document.body.appendChild(component) 31 | await component.updateComplete 32 | }) 33 | 34 | afterEach(() => { 35 | global.window.document.documentElement.innerHTML = ""; 36 | }) 37 | 38 | it("creates a new component", () => { 39 | expect(component.outerHTML).toEqual("Hello ${el.who}!
`, 41 | { defaults: { who: "noone" }}); 42 | 43 | // myComponent.test.ts 44 | import MyComponent from "./MyComponent.ts" 45 | 46 | describe("pure-lit", () => { 47 | type Props = { who: string } 48 | beforeEach(async () => { 49 | document.body.appendChild(MyComponent) 50 | await MyComponent.updateComplete 51 | }) 52 | 53 | afterEach(() => { 54 | document.body.removeChild(MyComponent) 55 | }) 56 | 57 | it("renders the default correctly", async () => { 58 | expect(MyComponent.shadowRoot?.innerHTML).toContain("Hello noone!") 59 | }); 60 | 61 | it("renders updated props correctlty", async () => { 62 | MyComponent.setAttribute("who", "John") 63 | await MyComponent.updateComplete 64 | expect(MyComponent.shadowRoot?.innerHTML).toContain("Hello John!
"); 65 | }); 66 | ``` 67 | 68 | Note that the tests in jest are not entirely side-effect free: In between the tests jsdom will not clean up the registry for the custom component. So if you create a component in the test, it's created only the first time. 69 | 70 | This means you cannot change the behavior of the component later (ie change the render method, or the defaults). To run it with a different scenario create a new test file. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # pure-lit 2 | 3 | [](https://www.npmjs.com/package/pure-lit) 4 | [](https://bundlephobia.com/result?p=pure-lit) 5 | [](https://snyk.io/test/github/MatthiasKainer/pure-lit?targetFile=package.json) 6 | [](https://bundlephobia.com/result?p=pure-lit) 7 |  8 |  9 |  10 |  11 | 12 | > [lit](https://lit.dev/) with pure functions. 13 | 14 | 15 | ## Install 16 | 17 | `npm install pure-lit` 18 | 19 | or add it to your page as module like this: 20 | 21 | `` 22 | 23 | ## Getting started 24 | 25 | [](https://pure-lit.org) 26 | 27 | The quickest way of getting started is by using JavaScript modules. 28 | 29 | Create a file `index.html` that looks like this: 30 | 31 | ```html 32 | 33 | 34 | 35 | 36 |Hello ${el.who}!
`, 27 | { defaults: { who: "noone" } }); 28 | events = {} 29 | Object.entries(eventListeners).forEach(([name, trigger]) => component.addEventListener(name, trigger)) 30 | document.body.appendChild(component) 31 | await component.updateComplete 32 | }) 33 | 34 | afterEach(() => { 35 | Object.entries(eventListeners).forEach(([name, trigger]) => component.removeEventListener(name, trigger)) 36 | document.body.removeChild(component) 37 | events = {} 38 | }) 39 | 40 | it("creates a new component", () => { 41 | expect(component.outerHTML).toEqual("Hello ${el.who}!
`), 11 | { defaults: { who: "noone" }}); 12 | document.body.appendChild(component) 13 | await component.updateComplete 14 | }) 15 | 16 | afterEach(() => { 17 | document.body.removeChild(component) 18 | }) 19 | 20 | it("creates a new component", () => { 21 | expect(component.outerHTML).toEqual("Hello ${el.who}!
`) 70 | : await Promise.reject(html`Noone to greet
`), 71 | { defaults: { who: undefined }}); 72 | const errorSlot = document.createElement("div") 73 | errorSlot.setAttribute("slot", "error") 74 | component.appendChild(errorSlot) 75 | document.body.appendChild(component) 76 | await component.updateComplete 77 | }) 78 | 79 | afterEach(() => { 80 | document.body.removeChild(component) 81 | }); 82 | 83 | afterAll(() => { 84 | (console.error as any).mockRestore(); 85 | }); 86 | 87 | it("creates a new component", () => { 88 | expect(component.outerHTML).toEqual("Noone to greet
`); 93 | }); 94 | 95 | it("renders the error slot correctly", () => { 96 | expect(component.shadowRoot?.textContent).toContain("Noone to greet") 97 | }); 98 | 99 | it("renders updated props correctlty", async () => { 100 | component.setAttribute("who", "John") 101 | await component.updateComplete 102 | expect(component.shadowRoot?.textContent).toContain("Hello John!"); 103 | }); 104 | }); -------------------------------------------------------------------------------- /docs/advanced-usecases.md: -------------------------------------------------------------------------------- 1 | # Advanced usage 2 | 3 | ## Dispatching events 4 | 5 | ### Using the dispatch-function 6 | 7 | If you want to dispatch a custom event, you don't have to write the `CustomEvent` code, you can either use a reducer or just use the `dispatch` method provided like so: 8 | 9 | ```typescript 10 | pureLit("todo-add", (element: LitElement) => { 11 | const todo = useState(element, ""); 12 | 13 | const onComplete = () => { 14 | if (todo.get().length > 0) { 15 | // dipatch a custom event "added" 16 | dispatch(element, "added", todo.get()); 17 | todo.set(""); 18 | } 19 | }; 20 | const onUpdate = ({ value }: { value: string }) => todo.set(value); 21 | return html` 22 |Hello ${el.whoIsThere}!
` 105 | }, 106 | { defaults: { whoIsThere: "noone" }}); 107 | ``` 108 | 109 | Using this via lit-html looks like this: 110 | 111 | ```js 112 | const who = "me"; 113 | return html`114 | Hello { 115 | clicks.set(clicks.value + 1) 116 | }}> ${name} ! 117 |
118 |119 | You were clicked ${clicks.value} times 120 |
`; 121 | }, 122 | { 123 | styles: [ 124 | css` 125 | :host { 126 | display: block; 127 | } 128 | `, 129 | css` 130 | em { 131 | color: red; 132 | } 133 | `, 134 | ], 135 | defaults: { 136 | id: 1, 137 | }, 138 | } 139 | ); 140 | ``` 141 | 142 | ## Example for a slow backend url 143 | 144 | ```typescript 145 | type Props = { id: number }; 146 | 147 | const baseUrl = "https://jsonplaceholder.typicode.com/users" 148 | 149 | pureLit("hello-incrementor", 150 | // this is an async function, allowing us to await 151 | async () => { 152 | // The api is fast, so we just wait for a second for fun 153 | await new Promise(resolve => setTimeout(resolve, 1000)) 154 | const { name } = await fetch("https://jsonplaceholder.typicode.com/users/1") 155 | .then((response) => response.json()); 156 | return html` 157 |158 | Hello ${name} ! 159 |
`; 160 | }, 161 | { 162 | // this will be shown while we wait for the promise to resolve 163 | suspense: html`please wait while loading...`, 164 | } 165 | ); 166 | ``` 167 | 168 | ## More examples 169 | 170 | For more examples see [MatthiasKainer/pure-lit-demos](https://github.com/MatthiasKainer/pure-lit-demos) -------------------------------------------------------------------------------- /src/pure-lit.ts: -------------------------------------------------------------------------------- 1 | import { html, LitElement, TemplateResult } from "lit"; 2 | import { 3 | RegisteredElements, 4 | RenderFunction, 5 | LitElementWithProps, 6 | PureArguments, 7 | AsyncRenderFunction, 8 | } from "./types"; 9 | import { toProperties, isDefault } from "./properties"; 10 | import { dispatch } from "./dispatch"; 11 | 12 | export const registered: RegisteredElements = {}; 13 | 14 | enum SuspenseStatus { 15 | INITAL, 16 | WAITING, 17 | COMPLETE, 18 | ERROR 19 | } 20 | 21 | class SuspenseRender