import { html, css, LitElement } from "lit";
import { customElement, property, query, state } from "lit/decorators.js";
import { checkFonts } from "../utils/check-fonts";
import { live } from "../utils/live";
import "./rich-action";
import { editorCommand } from "./rich-action";
@customElement("rich-toolbar")
export class RichToolbar extends LitElement {
static styles = css`
header {
width: 100%;
color: var(--rich-color);
display: flex;
flex-direction: row;
}
input[type="color"] {
-webkit-appearance: none;
border: none;
width: var(--icon-size);
height: var(--icon-size);
}
input[type="color"]::-webkit-color-swatch-wrapper {
padding: 0;
}
input[type="color"]::-webkit-color-swatch {
border: none;
}
`;
@live selection: Selection | null = null;
@query("#fg-color") fgColorInput!: HTMLInputElement;
@query("#bd-color") bdColorInput!: HTMLInputElement;
@state() fileHandle?: any;
@property({ type: Object, hasChanged: () => true }) node!: Element;
render() {
const tags = this.getTags();
return html`
{
const newLink = prompt("Write the URL here", "https://");
// Check if valid url
if (newLink && newLink.match(/^(http|https):\/\/[^ "]+$/)) {
editorCommand("createlink", newLink);
}
}}
>
this.fgColorInput.click()}
>
{
const input = e.target as HTMLInputElement;
editorCommand("forecolor", input.value);
}}
/>
this.bdColorInput.click()}
>
{
const input = e.target as HTMLInputElement;
editorCommand("backcolor", input.value);
}}
/>
({
name: font,
value: font,
})),
]}
>
{
if ("showOpenFilePicker" in window) {
// File system api
// @ts-ignore
const [fileHandle] = await window.showOpenFilePicker();
this.fileHandle = fileHandle;
if (fileHandle) {
const file = await fileHandle.getFile();
const contents = await file.text();
this.dispatchEvent(
new CustomEvent("set-content", {
detail: contents,
bubbles: true,
composed: true,
})
);
}
} else {
// Fallback to input
const input = document.createElement("input");
input.type = "file";
input.click();
input.onchange = async () => {
const file = input.files![0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
const data = reader.result as string;
this.dispatchEvent(
new CustomEvent("set-content", {
detail: data,
bubbles: true,
composed: true,
})
);
};
reader.readAsText(file);
}
};
}
}}
>
{
const contents = this.node.innerHTML;
if (this.fileHandle) {
const writable = await this.fileHandle.createWritable();
await writable.write(
[
``,
``,
` `,
` ${contents}`,
``,
].join("\n")
);
await writable.close();
} else {
// Download file
const url = window.URL.createObjectURL(
new Blob([contents], { type: "text/html" })
);
const link = document.createElement("a");
link.href = url;
link.download = "index.html";
link.click();
}
}}
>
`;
}
getTags() {
const { selection } = this;
let tags: string[] = [];
if (selection) {
if (selection.type === "Range") {
// @ts-ignore
let parentNode = selection?.baseNode;
if (parentNode) {
const checkNode = () => {
const tag = parentNode?.tagName?.toLowerCase()?.trim();
if (tag) tags.push(tag);
};
while (parentNode != null) {
checkNode();
parentNode = parentNode?.parentNode;
}
}
// Remove root tag
tags.pop();
} else {
const content = this.selection?.toString() || "";
tags = (content.match(/<[^>]+>/g) || [])
.filter((tag) => !tag.startsWith(""))
.map((tag) => tag.replace(/<|>/g, ""));
}
}
return tags;
}
}
declare global {
interface HTMLElementTagNameMap {
"rich-toolbar": RichToolbar;
}
}