static: rewrite custom components to typescript

This commit is contained in:
Jens Langhammer 2020-11-20 22:08:00 +01:00
parent 9c3bc4eb38
commit 1e1a002ab2
20 changed files with 444 additions and 282 deletions

View File

@ -64,9 +64,9 @@
{% endfor %} {% endfor %}
</td> </td>
<td> <td>
<button is="action-button" class="pf-c-button pf-m-primary" url="{% url 'passbook_api:admin_system_tasks-retry' pk=task.task_name %}"> <pb-action-button url="{% url 'passbook_api:admin_system_tasks-retry' pk=task.task_name %}">
{% trans 'Retry Task' %} {% trans 'Retry Task' %}
</button> </pb-action-button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -17,6 +17,7 @@
<link rel="stylesheet" type="text/css" href="{% static 'node_modules/@patternfly/patternfly/patternfly-addons.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'node_modules/@patternfly/patternfly/patternfly-addons.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'passbook/passbook.css' %}"> <link rel="stylesheet" type="text/css" href="{% static 'passbook/passbook.css' %}">
<script src="{% static 'passbook/main.js' %}" defer></script>
{% block head %} {% block head %}
{% endblock %} {% endblock %}
</head> </head>
@ -37,6 +38,5 @@
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
{% endblock %} {% endblock %}
<script src="{% static 'passbook/passbook.js' %}"></script>
</body> </body>
</html> </html>

View File

@ -38,6 +38,16 @@
"resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.59.1.tgz", "resolved": "https://registry.npmjs.org/@patternfly/patternfly/-/patternfly-4.59.1.tgz",
"integrity": "sha512-zk3aqg62JXMTzzJMJsyVgt5fXlcxUUkRKkaxUv/hwpjhGiyLexZ1l3Gupb9ziYl74p38KzbbfcfdnlFCwJZfgg==" "integrity": "sha512-zk3aqg62JXMTzzJMJsyVgt5fXlcxUUkRKkaxUv/hwpjhGiyLexZ1l3Gupb9ziYl74p38KzbbfcfdnlFCwJZfgg=="
}, },
"@rollup/plugin-typescript": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-6.1.0.tgz",
"integrity": "sha512-hJxaiE6WyNOsK+fZpbFh9CUijZYqPQuAOWO5khaGTUkM8DYNNyA2TDlgamecE+qLOG1G1+CwbWMAx3rbqpp6xQ==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.1.0",
"resolve": "^1.17.0"
}
},
"@rollup/pluginutils": { "@rollup/pluginutils": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
@ -591,6 +601,11 @@
} }
} }
}, },
"tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
},
"typescript": { "typescript": {
"version": "3.9.7", "version": "3.9.7",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",

View File

@ -11,9 +11,11 @@
"codemirror": "^5.58.2", "codemirror": "^5.58.2",
"lit-element": "^2.4.0", "lit-element": "^2.4.0",
"lit-html": "^1.3.0", "lit-html": "^1.3.0",
"rollup": "^2.33.2" "rollup": "^2.33.2",
"tslib": "^2.0.3"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-typescript": "^6.1.0",
"rollup-plugin-commonjs": "^10.1.0", "rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-minify-html-literals": "^1.2.5", "rollup-plugin-minify-html-literals": "^1.2.5",
"rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-node-resolve": "^5.2.0",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3,26 +3,24 @@ import commonjs from 'rollup-plugin-commonjs';
import minifyHTML from 'rollup-plugin-minify-html-literals'; import minifyHTML from 'rollup-plugin-minify-html-literals';
import { terser } from 'rollup-plugin-terser'; import { terser } from 'rollup-plugin-terser';
import sourcemaps from 'rollup-plugin-sourcemaps'; import sourcemaps from 'rollup-plugin-sourcemaps';
import typescript from '@rollup/plugin-typescript';
export default [{ export default [{
input: './src/passbook.js', input: './src/main.ts',
output: [ output: [
{ {
format: 'iife', format: 'iife',
dir: 'passbook', dir: 'passbook',
sourcemap: true, sourcemap: true
} }
], ],
plugins: [ plugins: [
typescript(),
resolve({browser: true}), resolve({browser: true}),
commonjs(), commonjs(),
sourcemaps(), sourcemaps(),
minifyHTML(), minifyHTML(),
terser(), terser(),
], ],
watch: {
clearScreen: false,
},
}]; }];

View File

@ -1,37 +1,33 @@
import { getCookie } from "./utils.js"; import { getCookie } from "./utils.js";
import { updateMessages } from "./Messages.js"; import { updateMessages } from "./Messages.js";
import { customElement, html, LitElement, property } from "lit-element";
const PRIMARY_CLASS = "pf-m-primary"; const PRIMARY_CLASS = "pf-m-primary";
const SUCCESS_CLASS = "pf-m-success"; const SUCCESS_CLASS = "pf-m-success";
const ERROR_CLASS = "pf-m-danger"; const ERROR_CLASS = "pf-m-danger";
const PROGRESS_CLASSES = ["pf-m-progress", "pf-m-in-progress"]; const PROGRESS_CLASSES = ["pf-m-progress", "pf-m-in-progress"];
class ActionButton extends HTMLButtonElement { @customElement("pb-action-button")
export class ActionButton extends LitElement {
constructor() { constructor() {
super(); super();
this.addEventListener('click', e => this.callAction()); this.querySelector("button")?.addEventListener('click', e => this.callAction());
} }
@property()
url: string = "";
isRunning = false; isRunning = false;
oldBody = "";
setLoading() { setLoading() {
this.isRunning = true;
this.classList.add(...PROGRESS_CLASSES); this.classList.add(...PROGRESS_CLASSES);
this.oldBody = this.innerText;
this.innerHTML = `<span class="pf-c-button__progress">
<span class="pf-c-spinner pf-m-md" role="progressbar" aria-valuetext="Loading...">
<span class="pf-c-spinner__clipper"></span>
<span class="pf-c-spinner__lead-ball"></span>
<span class="pf-c-spinner__tail-ball"></span>
</span>
</span>${this.oldBody}`;
} }
setDone(statusClass) { setDone(statusClass: string) {
this.isRunning = false; this.isRunning = false;
this.classList.remove(...PROGRESS_CLASSES); this.classList.remove(...PROGRESS_CLASSES);
this.innerText = this.oldBody;
this.classList.replace(PRIMARY_CLASS, statusClass); this.classList.replace(PRIMARY_CLASS, statusClass);
// Trigger messages to update // Trigger messages to update
updateMessages(); updateMessages();
@ -47,8 +43,8 @@ class ActionButton extends HTMLButtonElement {
this.setLoading(); this.setLoading();
const csrftoken = getCookie('passbook_csrf'); const csrftoken = getCookie('passbook_csrf');
const request = new Request( const request = new Request(
this.attributes["url"].value, this.url,
{ headers: { 'X-CSRFToken': csrftoken } } { headers: { 'X-CSRFToken': csrftoken! } }
); );
fetch(request, { fetch(request, {
method: "POST", method: "POST",
@ -60,6 +56,18 @@ class ActionButton extends HTMLButtonElement {
}); });
} }
} render() {
return html`<button class="pf-c-button pf-m-primary">
${this.isRunning ? html`
<span class="pf-c-button__progress">
<span class="pf-c-spinner pf-m-md" role="progressbar" aria-valuetext="Loading...">
<span class="pf-c-spinner__clipper"></span>
<span class="pf-c-spinner__lead-ball"></span>
<span class="pf-c-spinner__tail-ball"></span>
</span>
</span>` : ""}
<slot></slot>
</button>`;
}
customElements.define('action-button', ActionButton, { extends: 'button' }); }

View File

@ -0,0 +1,23 @@
import { customElement, html, LitElement } from "lit-element";
@customElement("pb-dropdown")
export class DropdownButton extends LitElement {
constructor() {
super()
const menu = <HTMLElement>this.querySelector('.pf-c-dropdown__menu')!;
this.querySelectorAll("button").forEach(btn => {
btn.addEventListener("click", e => {
menu.hidden = !menu.hidden;
});
btn.addEventListener("blur", e => {
menu.hidden = true;
});
});
}
render() {
return html`<slot></slot>`;
}
}

View File

@ -1,37 +1,43 @@
import { LitElement, html } from 'lit-element'; import { LitElement, html, customElement, property } from 'lit-element';
class FetchFillSlot extends LitElement { interface ComparisonHash {
[key: string]: (a: any, b: any) => boolean
}
static get properties() { @customElement("fetch-fill-slot")
return { export class FetchFillSlot extends LitElement {
url: { type: String },
key: { type: String },
value: { type: Number },
};
}
comparison(slotName) { @property()
var comparisonOperatorsHash = { url: string = "";
'<': function (a, b) { return a < b; },
'>': function (a, b) { return a > b; }, @property()
'>=': function (a, b) { return a >= b; }, key: string = "";
'<=': function (a, b) { return a <= b; },
'==': function (a, b) { return a == b; }, @property()
'!=': function (a, b) { return a != b; }, value: string = "";
'===': function (a, b) { return a === b; },
'!==': function (a, b) { return a !== b; }, comparison(slotName: string) {
let comparisonOperatorsHash = <ComparisonHash>{
'<': function (a: any, b: any) { return a < b; },
'>': function (a: any, b: any) { return a > b; },
'>=': function (a: any, b: any) { return a >= b; },
'<=': function (a: any, b: any) { return a <= b; },
'==': function (a: any, b: any) { return a == b; },
'!=': function (a: any, b: any) { return a != b; },
'===': function (a: any, b: any) { return a === b; },
'!==': function (a: any, b: any) { return a !== b; },
}; };
const tokens = slotName.split(" "); const tokens = slotName.split(" ");
if (tokens.length < 3) { if (tokens.length < 3) {
throw new Error("nah"); throw new Error("nah");
} }
let a = tokens[0]; let a: any = tokens[0];
if (a === "value") { if (a === "value") {
a = this.value; a = this.value;
} else { } else {
a = parseInt(a, 10); a = parseInt(a, 10);
} }
let b = tokens[2]; let b: any = tokens[2];
if (b === "value") { if (b === "value") {
b = this.value; b = this.value;
} else { } else {
@ -54,7 +60,7 @@ class FetchFillSlot extends LitElement {
} }
let selectedSlot = ""; let selectedSlot = "";
this.querySelectorAll("[slot]").forEach(slot => { this.querySelectorAll("[slot]").forEach(slot => {
const comp = slot.getAttribute("slot"); const comp = slot.getAttribute("slot")!;
if (this.comparison(comp)) { if (this.comparison(comp)) {
selectedSlot = comp; selectedSlot = comp;
} }
@ -65,5 +71,3 @@ class FetchFillSlot extends LitElement {
return html`<slot name=${selectedSlot}></slot>`; return html`<slot name=${selectedSlot}></slot>`;
} }
} }
customElements.define('fetch-fill-slot', FetchFillSlot);

View File

@ -1,14 +1,25 @@
import { LitElement, html } from 'lit-element'; import { LitElement, html, customElement, property } from 'lit-element';
import { updateMessages } from "./Messages.js"; import { updateMessages } from "./Messages";
class FlowShellCard extends LitElement { enum ResponseType {
redirect,
template
}
static get properties() { interface Response {
return { type: ResponseType;
flowBodyUrl: { type: String }, to?: string;
flowBody: { type: String }, body?: string;
}; }
}
@customElement("flow-shell-card")
export class FlowShellCard extends LitElement {
@property()
flowBodyUrl: string = "";
@property()
flowBody?: string = undefined;
createRenderRoot() { createRenderRoot() {
return this; return this;
@ -30,12 +41,12 @@ class FlowShellCard extends LitElement {
}); });
} }
async updateCard(data) { async updateCard(data: Response) {
switch (data.type) { switch (data.type) {
case "redirect": case ResponseType.redirect:
window.location = data.to window.location.assign(data.to!);
break; break;
case "template": case ResponseType.template:
this.flowBody = data.body; this.flowBody = data.body;
await this.requestUpdate(); await this.requestUpdate();
this.checkAutofocus(); this.checkAutofocus();
@ -56,26 +67,26 @@ class FlowShellCard extends LitElement {
} }
checkAutofocus() { checkAutofocus() {
const autofocusElement = this.querySelector("[autofocus]"); const autofocusElement = <HTMLElement>this.querySelector("[autofocus]");
if (autofocusElement !== null) { if (autofocusElement !== null) {
autofocusElement.focus(); autofocusElement.focus();
} }
} }
updateFormAction(form) { updateFormAction(form: HTMLFormElement) {
for (let index = 0; index < form.elements.length; index++) { for (let index = 0; index < form.elements.length; index++) {
const element = form.elements[index]; const element = <HTMLInputElement>form.elements[index];
if (element.value === form.action) { if (element.value === form.action) {
console.log("pb-flow: Found Form action URL in form elements, not changing form action."); console.log("pb-flow: Found Form action URL in form elements, not changing form action.");
return false; return false;
} }
} }
form.action = this.flowBodyUrl; form.action = this.flowBodyUrl;
console.log(`pb-flow: updated form.action ${this.flowBodyUrl}`); console.log(`passbook/flows: updated form.action ${this.flowBodyUrl}`);
return true; return true;
} }
checkAutosubmit(form) { checkAutosubmit(form: HTMLFormElement) {
if ("autosubmit" in form.attributes) { if ("autosubmit" in form.attributes) {
return form.submit(); return form.submit();
} }
@ -83,11 +94,11 @@ class FlowShellCard extends LitElement {
setFormSubmitHandlers() { setFormSubmitHandlers() {
this.querySelectorAll("form").forEach(form => { this.querySelectorAll("form").forEach(form => {
console.log(`pb-flow: Checking for autosubmit attribute ${form}`); console.log(`passbook/flows: Checking for autosubmit attribute ${form}`);
this.checkAutosubmit(form); this.checkAutosubmit(form);
console.log(`pb-flow: Setting action for form ${form}`); console.log(`passbook/flows: Setting action for form ${form}`);
this.updateFormAction(form); this.updateFormAction(form);
console.log(`pb-flow: Adding handler for form ${form}`); console.log(`passbook/flows: Adding handler for form ${form}`);
form.addEventListener('submit', (e) => { form.addEventListener('submit', (e) => {
e.preventDefault(); e.preventDefault();
let formData = new FormData(form); let formData = new FormData(form);
@ -107,7 +118,7 @@ class FlowShellCard extends LitElement {
}); });
} }
errorMessage(error) { errorMessage(error: string) {
this.flowBody = ` this.flowBody = `
<style> <style>
.pb-exception { .pb-exception {
@ -141,10 +152,9 @@ class FlowShellCard extends LitElement {
render() { render() {
if (this.flowBody !== undefined) { if (this.flowBody !== undefined) {
return html([this.flowBody]); // return html(<TemplateStringsArray>[this.flowBody]);
return html`${this.flowBody}`;
} }
return this.loading(); return this.loading();
} }
} }
customElements.define('flow-shell-card', FlowShellCard);

View File

@ -1,28 +1,34 @@
import { LitElement, html } from 'lit-element'; import { LitElement, html, customElement, property } from 'lit-element';
const LEVEL_ICON_MAP = { const LEVEL_ICON_MAP: { [key: string]: string } = {
"error": "fas fa-exclamation-circle", "error": "fas fa-exclamation-circle",
"warning": "fas fa-exclamation-triangle", "warning": "fas fa-exclamation-triangle",
"success": "fas fa-check-circle", "success": "fas fa-check-circle",
"info": "fas fa-info", "info": "fas fa-info",
}; };
let ID = function (prefix) { let ID = function (prefix: string) {
return prefix + Math.random().toString(36).substr(2, 9); return prefix + Math.random().toString(36).substr(2, 9);
}; };
export function updateMessages() { export function updateMessages() {
document.querySelector("pb-messages").fetchMessages(); const messageElement = <Messages>document?.querySelector("pb-messages");
messageElement.fetchMessages();
} }
class Messages extends LitElement { interface Message {
level_tag: string;
message: string;
}
static get properties() { @customElement("pb-messages")
return { export class Messages extends LitElement {
url: { type: String },
messages: { type: Array }, @property()
}; url: string = "";
}
@property()
messages: string[] = [];
createRenderRoot() { createRenderRoot() {
return this; return this;
@ -34,15 +40,15 @@ class Messages extends LitElement {
fetchMessages() { fetchMessages() {
return fetch(this.url).then(r => r.json()).then(r => this.messages = r).then((r) => { return fetch(this.url).then(r => r.json()).then(r => this.messages = r).then((r) => {
const container = this.querySelector(".pf-c-alert-group"); const container = <HTMLElement>this.querySelector(".pf-c-alert-group")!;
r.forEach(message => { r.forEach((message: Message) => {
const messageElement = this.renderMessage(message); const messageElement = this.renderMessage(message);
container.appendChild(messageElement); container.appendChild(messageElement);
}); });
}); });
} }
renderMessage(message) { renderMessage(message: Message): ChildNode {
const id = ID("pb-message"); const id = ID("pb-message");
const el = document.createElement("template"); const el = document.createElement("template");
el.innerHTML = `<li id=${id} class="pf-c-alert-group__item"> el.innerHTML = `<li id=${id} class="pf-c-alert-group__item">
@ -56,14 +62,12 @@ class Messages extends LitElement {
</div> </div>
</li>`; </li>`;
setTimeout(() => { setTimeout(() => {
this.querySelector(`#${id}`).remove(); this.querySelector(`#${id}`)?.remove();
}, 1500); }, 1500);
return el.content.firstChild; return el.content.firstChild!;
} }
render() { render() {
return html`<ul class="pf-c-alert-group pf-m-toast"></ul>`; return html`<ul class="pf-c-alert-group pf-m-toast"></ul>`;
} }
} }
customElements.define('pb-messages', Messages);

View File

@ -0,0 +1,58 @@
import { customElement, html, LitElement, property } from "lit-element";
const PRIMARY_CLASS = "pf-m-primary";
const SUCCESS_CLASS = "pf-m-success";
const ERROR_CLASS = "pf-m-danger";
const PROGRESS_CLASSES = ["pf-m-progress", "pf-m-in-progress"];
@customElement("pb-modal-button")
export class ModalButton extends LitElement {
@property()
href: string = "";
constructor() {
super();
this.addEventListener('click', e => this.callAction(e));
}
getModal() {
return html`<div class="pf-c-backdrop">
<div class="pf-l-bullseye">
<div class="pf-c-modal-box pf-m-md" role="dialog" aria-modal="true" aria-labelledby="modal-md-title" aria-describedby="modal-md-description">
<button class="pf-c-button pf-m-plain" type="button" aria-label="Close dialog">
<i class="fas fa-times" aria-hidden="true"></i>
</button>
<header class="pf-c-modal-box__header">
<h1 class="pf-c-modal-box__title" id="modal-md-title">This is a long header title that will truncate because modal titles should be very short. Use the modal body to provide more info.</h1>
</header>
<div class="pf-c-modal-box__body">
<p id="modal-md-description">The "aria-describedby" attribute can be applied to any text that adequately describes the modal's purpose. It does not have to be assigned to ".pf-c-modal-box__body"</p>
<p>Form here</p>
</div>
<footer class="pf-c-modal-box__footer">
<button class="pf-c-button pf-m-primary" type="button">Save</button>
<button class="pf-c-button pf-m-link" type="button">Cancel</button>
</footer>
</div>
</div>
</div>`;
}
callAction(e: MouseEvent) {
e.preventDefault();
const request = new Request(
this.href,
);
fetch(request, {
method: "POST",
mode: 'same-origin',
}).then(r => {
// this.
}).catch(() => {
// this.setDone(ERROR_CLASS);
});
}
}

View File

@ -1,9 +1,10 @@
import { LitElement, html } from 'lit-element'; import { LitElement, html, customElement } from 'lit-element';
class Tabs extends LitElement { @customElement("pb-tabs")
export class Tabs extends LitElement {
_currentPage = ""; _currentPage? = "";
_firstPage = ""; _firstPage? = "";
get currentPage() { get currentPage() {
return this._currentPage return this._currentPage
@ -12,9 +13,9 @@ class Tabs extends LitElement {
set currentPage(value) { set currentPage(value) {
try { try {
// Show active tab page // Show active tab page
this.querySelector(`.pf-c-tab-content[tab-name='${value}']`).removeAttribute("hidden"); this.querySelector(`.pf-c-tab-content[tab-name='${value}']`)?.removeAttribute("hidden");
// Update active status on buttons // Update active status on buttons
this.querySelector(`.pf-c-tabs__item[tab-name='${value}']`).classList.add("pf-m-current"); this.querySelector(`.pf-c-tabs__item[tab-name='${value}']`)?.classList.add("pf-m-current");
// Hide other tab pages // Hide other tab pages
this.querySelectorAll(`.pf-c-tab-content:not([tab-name='${value}'])`).forEach((el) => { this.querySelectorAll(`.pf-c-tab-content:not([tab-name='${value}'])`).forEach((el) => {
el.setAttribute("hidden", ""); el.setAttribute("hidden", "");
@ -24,7 +25,7 @@ class Tabs extends LitElement {
el.classList.remove("pf-m-current"); el.classList.remove("pf-m-current");
}); });
// Update window hash // Update window hash
window.location.hash = value; window.location.hash = `#${value}`;
this._currentPage = value; this._currentPage = value;
} catch (e) { } catch (e) {
this.currentPage = this._firstPage; this.currentPage = this._firstPage;
@ -36,7 +37,7 @@ class Tabs extends LitElement {
} }
firstUpdated() { firstUpdated() {
this._firstPage = this.querySelector(".pf-c-tab-content").getAttribute("tab-name"); this._firstPage = this.querySelector(".pf-c-tab-content")?.getAttribute("tab-name")!;
if (window.location.hash) { if (window.location.hash) {
this.currentPage = window.location.hash; this.currentPage = window.location.hash;
} else { } else {
@ -44,12 +45,10 @@ class Tabs extends LitElement {
} }
this.querySelectorAll(".pf-c-tabs__item > button").forEach((button) => { this.querySelectorAll(".pf-c-tabs__item > button").forEach((button) => {
button.addEventListener("click", (e) => { button.addEventListener("click", (e) => {
let tabPage = button.parentElement.getAttribute("tab-name"); let tabPage = button.parentElement?.getAttribute("tab-name")!;
this.currentPage = tabPage; this.currentPage = tabPage;
}) })
}); });
} }
} }
customElements.define('pb-tabs', Tabs);

View File

@ -1,18 +1,3 @@
import './FetchFillSlot.js';
import './ActionButton.js';
import './Messages.js';
import './FlowShellCard.js';
import './Tabs.js';
// Button Dropdowns
document.querySelectorAll("button.pf-c-dropdown__toggle").forEach((b) => {
b.addEventListener('click', (e) => {
const parent = e.target.closest('.pf-c-dropdown');
const menu = parent.querySelector('.pf-c-dropdown__menu');
menu.hidden = !menu.hidden;
});
});
// Search clearing // Search clearing
document.querySelectorAll("input[type=search]").forEach((si) => { document.querySelectorAll("input[type=search]").forEach((si) => {
si.addEventListener("search", (e) => { si.addEventListener("search", (e) => {

View File

@ -0,0 +1,9 @@
import "./legacy.js";
import './ActionButton';
import './Dropdown';
import './FetchFillSlot';
import './FlowShellCard';
import './Messages';
import './Tabs';
import './ModalButton';

View File

@ -1,4 +1,4 @@
export function getCookie(name) { export function getCookie(name: string) {
let cookieValue = null; let cookieValue = null;
if (document.cookie && document.cookie !== '') { if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';'); const cookies = document.cookie.split(';');

View File

@ -0,0 +1,18 @@
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"experimentalDecorators": true,
"sourceMap": true,
"target": "es2017",
"module": "es2015",
"moduleResolution": "node",
"lib": [
"es2017",
"dom",
"dom.iterable"
],
}
}