import { LitElement, html } from "lit"
import { classMap } from "lit/directives/class-map.js"
import { customElement, property } from "lit/decorators.js"
import elementStyles from "./split-flap.scss"
interface Letter {
Character: string
Revealed: boolean
}
/**
* A Split Flap web component.
*
*/
@customElement("split-flap")
export class SplitFlap extends LitElement {
static override styles = elementStyles
private _message = "Set Me"
private _lines: Array> = []
private _ranDisplay = false
/**
* The name to say "Hello" to.
*/
@property()
public set message(m: string) {
this._message = m
let currentLine: Array = []
for (const letter of [...m.toUpperCase()]) {
const isLineBreak = /\r|\n/.exec(letter)
if (isLineBreak) {
this._lines.push(currentLine)
currentLine = []
continue
}
currentLine.push({ Character: letter, Revealed: false })
}
this._lines.push(currentLine)
if (this._lines.length == 1) {
return
}
const maxChars = Math.max(...this._lines.map((l) => l.length))
for (const line of this._lines) {
if (line.length == maxChars) {
continue
}
for (let i = 0; i <= maxChars - line.length; i++) {
line.push({
Character: " ",
Revealed: false,
})
}
}
}
public get message(): string {
return this._message
}
protected override render() {
return html`
${this._lines.map((line, row) => {
return line.map((letter) => {
const classes = { revealed: letter.Revealed }
return html`
${letter.Character}
${letter.Character}
`
})
})}
`
}
protected override updated(): void {
if (this._ranDisplay) {
return
}
this._ranDisplay = true
let nextTimeout = Math.random() * 300 + 200
for (const line of this._lines) {
for (const letter of line) {
setTimeout(() => {
letter.Revealed = true
this.requestUpdate()
}, nextTimeout)
nextTimeout += Math.random() * 300 + 200
}
}
}
}
declare global {
interface HTMLElementTagNameMap {
"split-flap": SplitFlap
}
}