diff --git a/pyscriptjs/examples/todo-pylist.html b/pyscriptjs/examples/todo-pylist.html
index 9a8e2cb..e38be33 100644
--- a/pyscriptjs/examples/todo-pylist.html
+++ b/pyscriptjs/examples/todo-pylist.html
@@ -18,28 +18,27 @@
-
-
-
-
-
-
-
To Do List
-
+ To Do List
+
+
-
+
diff --git a/pyscriptjs/src/components/pybutton.ts b/pyscriptjs/src/components/pybutton.ts
new file mode 100644
index 0000000..452ee43
--- /dev/null
+++ b/pyscriptjs/src/components/pybutton.ts
@@ -0,0 +1,64 @@
+import { BaseEvalElement } from './base';
+import { addClasses, ltrim, htmlDecode } from '../utils';
+
+export class PyButton extends BaseEvalElement {
+ shadow: ShadowRoot;
+ wrapper: HTMLElement;
+ theme: string;
+ widths: Array;
+ label: string;
+ mount_name: string;
+ constructor() {
+ super();
+
+ // attach shadow so we can preserve the element original innerHtml content
+ // this.shadow = this.attachShadow({ mode: 'open'});
+
+ // this.wrapper = document.createElement('slot');
+ // this.shadow.appendChild(this.wrapper);
+ if (this.hasAttribute('label')) {
+ this.label = this.getAttribute('label');
+ }
+ }
+
+
+ connectedCallback() {
+ this.code = htmlDecode(this.innerHTML);
+ this.mount_name = this.id.split("-").join("_");
+ this.innerHTML = '';
+
+ let mainDiv = document.createElement('button');
+ mainDiv.innerHTML = this.label;
+ addClasses(mainDiv, ["p-2", "text-white", "bg-blue-600", "border", "border-blue-600", "rounded"]);
+
+ mainDiv.id = this.id;
+ this.id = `${this.id}-container`;
+
+ this.appendChild(mainDiv);
+ this.code = this.code.split("self").join(this.mount_name);
+ let registrationCode = `${this.mount_name} = Element("${ mainDiv.id }")`;
+ if (this.code.includes("def on_focus")){
+ this.code = this.code.replace("def on_focus", `def on_focus_${this.mount_name}`);
+ registrationCode += `\n${this.mount_name}.element.onfocus = on_focus_${this.mount_name}`
+ }
+
+ if (this.code.includes("def on_click")){
+ this.code = this.code.replace("def on_click", `def on_click_${this.mount_name}`);
+ registrationCode += `\n${this.mount_name}.element.onclick = on_click_${this.mount_name}`
+ }
+
+ // now that we appended and the element is attached, lets connect with the event handlers
+ // defined for this widget
+ setTimeout(() => {
+ this.eval(this.code).then(() => {
+ this.eval(registrationCode).then(() => {
+ console.log('registered handlers');
+ });
+ });
+ }, 4000);
+
+ console.log('py-button connected');
+ }
+ }
+
+
\ No newline at end of file
diff --git a/pyscriptjs/src/components/pytitle.ts b/pyscriptjs/src/components/pytitle.ts
new file mode 100644
index 0000000..633fff6
--- /dev/null
+++ b/pyscriptjs/src/components/pytitle.ts
@@ -0,0 +1,37 @@
+import { BaseEvalElement } from './base';
+import { addClasses, ltrim, htmlDecode } from '../utils';
+
+export class PyTitle extends BaseEvalElement {
+ shadow: ShadowRoot;
+ wrapper: HTMLElement;
+ theme: string;
+ widths: Array;
+ label: string;
+ mount_name: string;
+ constructor() {
+ super();
+ }
+
+
+ connectedCallback() {
+ this.label = htmlDecode(this.innerHTML);
+ this.mount_name = this.id.split("-").join("_");
+ this.innerHTML = '';
+
+ let mainDiv = document.createElement('div');
+ let divContent = document.createElement('h1')
+
+ addClasses(mainDiv, ["text-center", "w-full", "mb-8"]);
+ addClasses(divContent, ["text-3xl", "font-bold", "text-gray-800", "uppercase", "tracking-tight"]);
+ divContent.innerHTML = this.label;
+
+ mainDiv.id = this.id;
+ this.id = `${this.id}-container`;
+ mainDiv.appendChild(divContent);
+ this.appendChild(mainDiv);
+
+ console.log('py-title connected');
+ }
+ }
+
+
\ No newline at end of file
diff --git a/pyscriptjs/src/main.ts b/pyscriptjs/src/main.ts
index 1dfbf9b..6eb5679 100644
--- a/pyscriptjs/src/main.ts
+++ b/pyscriptjs/src/main.ts
@@ -4,12 +4,16 @@ import { PyScript } from "./components/pyscript";
import { PyRepl } from "./components/pyrepl";
import { PyEnv } from "./components/pyenv";
import { PyBox } from "./components/pybox";
+import { PyButton } from "./components/pybutton";
+import { PyTitle } from "./components/pytitle";
import { PyWidget } from "./components/base";
let xPyScript = customElements.define('py-script', PyScript);
let xPyRepl = customElements.define('py-repl', PyRepl);
let xPyEnv = customElements.define('py-env', PyEnv);
let xPyBox = customElements.define('py-box', PyBox);
+let xPyButton = customElements.define('py-button', PyButton);
+let xPyTitle = customElements.define('py-title', PyTitle);
let xPyWidget = customElements.define('py-register-widget', PyWidget);
diff --git a/pyscriptjs/src/utils.ts b/pyscriptjs/src/utils.ts
index d9912bf..ac9f83d 100644
--- a/pyscriptjs/src/utils.ts
+++ b/pyscriptjs/src/utils.ts
@@ -9,4 +9,29 @@ const getLastPath = function (str) {
return str.split('\\').pop().split('/').pop();
}
-export {addClasses, getLastPath}
+function htmlDecode(input) {
+ var doc = new DOMParser().parseFromString(input, "text/html");
+ return ltrim(doc.documentElement.textContent);
+}
+
+function ltrim(code: string): string {
+ const lines = code.split("\n")
+ if (lines.length == 0)
+ return code
+
+ const lengths = lines
+ .filter((line) => line.trim().length != 0)
+ .map((line) => {
+ const [prefix] = line.match(/^\s*/)
+ return prefix.length
+ })
+
+ const k = Math.min(...lengths)
+
+ if (k != 0)
+ return lines.map((line) => line.substring(k)).join("\n")
+ else
+ return code
+}
+
+export {addClasses, getLastPath, ltrim, htmlDecode}