diff --git a/demo/chains-of-thought/main.ts b/demo/chains-of-thought/main.ts index 33b3ce4..be3b423 100644 --- a/demo/chains-of-thought/main.ts +++ b/demo/chains-of-thought/main.ts @@ -129,7 +129,7 @@ async function openFile(showPicker = true) { try { const text = await fileSaver.open(showPicker); const json = JSON.parse(text || '{ "thoughts": [], "connections": [] }'); - main.innerHTML = renderChainOfThought(json); + main.setHTMLUnsafe(renderChainOfThought(json)); } catch (e) { // No file handler was persisted or the file is invalid JSON. console.error(e); diff --git a/demo/src/record-player.ts b/demo/src/record-player.ts index 17a9356..64fe9df 100644 --- a/demo/src/record-player.ts +++ b/demo/src/record-player.ts @@ -1,5 +1,5 @@ // Ported from https://github.com/bitu467/record-player -import { css } from '../../src/common/tags'; +import { css, html } from '../../src/common/tags'; const styles = css` ::slotted(*) { @@ -236,18 +236,17 @@ export class RecordPlayer extends HTMLElement { const shadow = this.attachShadow({ mode: 'open' }); shadow.adoptedStyleSheets.push(styles); - shadow.innerHTML = ` -
-
-
-
-
-
-
- - -
-`; + shadow.setHTMLUnsafe(html`
+
+
+
+
+
+
+ + +
+ `); this.#volumeInput = shadow.querySelector('input[type="range"]')!; this.#volumeInput.addEventListener('input', this); diff --git a/src/folk-llm.ts b/src/folk-llm.ts index 0f38f77..1ecc477 100644 --- a/src/folk-llm.ts +++ b/src/folk-llm.ts @@ -91,7 +91,7 @@ export class FolkLLM extends HTMLElement { const stream = await this.#session.promptStreaming(this.prompt); for await (const chunk of stream) { - this.#shadow.innerHTML = chunk; + this.#shadow.setHTMLUnsafe(chunk); } this.dispatchEvent(new Event('finished')); diff --git a/src/folk-shape.ts b/src/folk-shape.ts index d332ccc..11819a1 100644 --- a/src/folk-shape.ts +++ b/src/folk-shape.ts @@ -258,7 +258,7 @@ export class FolkShape extends HTMLElement { // Ideally we would creating these lazily on first focus, but the resize handlers need to be around for delegate focus to work. // Maybe can add the first resize handler here, and lazily instantiate the rest when needed? // I can see it becoming important at scale - this.#shadow.innerHTML = html` + this.#shadow.setHTMLUnsafe(html` @@ -266,7 +266,7 @@ export class FolkShape extends HTMLElement { -
`; +
`); this.#handles = Object.fromEntries( Array.from(this.#shadow.querySelectorAll('[part]')).map((el) => [ diff --git a/src/folk-space-radial.ts b/src/folk-space-radial.ts index 456a492..2552c94 100644 --- a/src/folk-space-radial.ts +++ b/src/folk-space-radial.ts @@ -46,7 +46,7 @@ export class FolkSpaceRadial extends HTMLElement { this.#centerPoint = document.createElement('div'); this.#centerPoint.className = 'center-point'; - this.#shadow.innerHTML = html` `; + this.#shadow.setHTMLUnsafe(html` `); this.#shadow.appendChild(this.#centerPoint); // Listen for changes in the slot to layout children when they change diff --git a/src/folk-space.ts b/src/folk-space.ts index da0f0d4..323e8e7 100644 --- a/src/folk-space.ts +++ b/src/folk-space.ts @@ -1,4 +1,4 @@ -import { html } from './common/tags'; +import { html, css } from './common/tags'; declare global { interface HTMLElementTagNameMap { @@ -6,6 +6,44 @@ declare global { } } +const styles = css` + :host { + display: block; + perspective: 1000px; + position: relative; + width: 100%; + height: 100%; + } + + .space { + position: absolute; + width: 100%; + height: 100%; + transform-style: preserve-3d; + transform-origin: center; + transition: transform 0.6s; + } + + .space.rotate { + transform: rotateX(-90deg); + } + + .face { + position: absolute; + width: 100%; + height: 100%; + backface-visibility: hidden; + } + + .front { + transform: rotateX(0deg); + } + + .back { + transform: rotateX(90deg); + } +`; + export class FolkSpace extends HTMLElement { static tagName = 'folk-space'; @@ -14,47 +52,14 @@ export class FolkSpace extends HTMLElement { customElements.define(this.tagName, this); } + #shadow = this.attachShadow({ mode: 'open' }); + constructor() { super(); - const shadowRoot = this.attachShadow({ mode: 'open' }); - shadowRoot.innerHTML = html` - + this.#shadow.setHTMLUnsafe(html`
@@ -63,7 +68,7 @@ export class FolkSpace extends HTMLElement {
- `; + `); } transition() { diff --git a/src/folk-spreadsheet.ts b/src/folk-spreadsheet.ts index 5717e26..ae2f4cb 100644 --- a/src/folk-spreadsheet.ts +++ b/src/folk-spreadsheet.ts @@ -1,4 +1,4 @@ -import { css } from './common/tags'; +import { css, html } from './common/tags'; // hardcoded column and row numbers const styles = css` @@ -214,14 +214,14 @@ export class FolkSpreadsheet extends HTMLElement { .join('\n')} `; - this.#shadow.innerHTML = ` + this.#shadow.setHTMLUnsafe(html` ${columnHeaders} ${rowHeaders} ${style} - `; + `); this.#textarea = this.#shadow.querySelector('textarea')!; } diff --git a/src/folk-weather.ts b/src/folk-weather.ts index 19ff2dc..b1916f5 100644 --- a/src/folk-weather.ts +++ b/src/folk-weather.ts @@ -1,3 +1,5 @@ +import { html } from './common/tags'; + interface Weather { temperature: string; windSpeed: string; @@ -60,12 +62,12 @@ export class FolkWeather extends HTMLElement { #renderResults() { if (this.#results === null) { - this.innerHTML = ''; + this.setHTMLUnsafe(''); return; } - this.innerHTML = ` + this.setHTMLUnsafe(html`

Temperature: ${this.#results.temperature}

Wind Speed: ${this.#results.windSpeed}

- `; + `); } }