Deprecate py-button, py-inputbox, py-box and py-title (#931)

This commit is contained in:
Fábio Rosado
2022-11-14 16:29:28 +00:00
committed by GitHub
parent be9b9f66d3
commit adfa9a9b05
15 changed files with 179 additions and 24 deletions

View File

@@ -417,11 +417,11 @@ The following tags can be used to add visual attributes to your HTML page.
| Tag | Description |
| --- | ----------- |
| `<py-inputbox>` | Adds an input box that can be used to prompt users to enter input values. |
| `<py-box>` | Creates a container object that can be used to host one or more visual components that define how elements of `<py-box>` should align and show on the page. |
| `<py-button>` | Adds a button to which authors can add labels and event handlers for actions on the button, such as `on_focus` or `on_click`. |
| `<py-title>` | Adds a static text title component that styles the text inside the tag as a page title. |
| `<py-inputbox>` | (Deprecated) Adds an input box that can be used to prompt users to enter input values. |
| `<py-box>` | (Deprecated) Creates a container object that can be used to host one or more visual components that define how elements of `<py-box>` should align and show on the page. |
| `<py-button>` | (Deprecated) Adds a button to which authors can add labels and event handlers for actions on the button, such as `on_focus` or `on_click`. |
| `<py-title>` | (Deprecated) Adds a static text title component that styles the text inside the tag as a page title. |
```{note}
All the elements above are experimental and not implemented at their full functionality. Use them with the understanding that the APIs or full support might change or be removed until the visual components are more mature.
These elements have been deprecated, we suggest that you use native elements and attach the respective `py-` attribute. For example for `<py-button>` you can write `<button py-click="function()">`
```

View File

@@ -24,9 +24,9 @@
[[fetch]]
files = ["./utils.py", "./antigravity.py"]
</py-config>
<py-box widths="2/3;1/3">
<div>
<py-repl id="my-repl" auto-generate="true"> </py-repl>
<div id="output" class="p-4"></div>
</py-box>
</div>
</body>
</html>

View File

@@ -17,8 +17,12 @@
</py-config>
<py-script>
from js import document
from pyodide.ffi.wrappers import add_event_listener
def add_task(*ags, **kws):
# create a new dictionary representing the new task
new_task_content = Element("new-task-content")
task = { "content": new_task_content.value, "done": False, "created_at": dt.now() }
# add a new task to the list and tell it to use the `content` key to show in the UI
@@ -28,22 +32,28 @@
# clear the inputbox element used to create the new task
new_task_content.clear()
def on_click(evt):
add_task()
def handle_keypress(evt):
if evt.key == "Enter":
add_task()
add_event_listener(
document.getElementById("new-task-content"),
"keypress",
handle_keypress
)
</py-script>
</head>
<body>
<py-title>To Do List</py-title>
<py-box widths="4/5;1/5">
<py-inputbox id="new-task-content">
def on_keypress(e):
if (e.code == "Enter"):
add_task()
</py-inputbox>
<py-button id="new-task-btn" label="Add Task!">
def on_click(evt):
add_task()
</py-button>
</py-box>
<h1>To Do List</h1>
<div class="py-box">
<input id="new-task-content" />
<button py-click="add_task()" id="new-task-btn" class="py-button">Add Task!</button>
</div>
<py-list id="myList"></py-list>
<py-repl id="my-repl" auto-generate="true"> </py-repl>

View File

@@ -1,4 +1,4 @@
import { getAttribute, addClasses } from '../utils';
import { getAttribute, addClasses, createDeprecationWarning } from '../utils';
import { getLogger } from '../logger';
const logger = getLogger('py-box');
@@ -20,6 +20,11 @@ export class PyBox extends HTMLElement {
}
connectedCallback() {
const deprecationMessage = (
'<p>The element &lt;py-box&gt; is deprecated, you should create a ' +
'div with "py-box" class name instead. For example: &lt;div class="py-box"&gt; '
)
createDeprecationWarning(deprecationMessage, "py-box")
const mainDiv = document.createElement('div');
addClasses(mainDiv, ['py-box']);

View File

@@ -1,4 +1,4 @@
import { getAttribute, addClasses, htmlDecode, ensureUniqueId } from '../utils';
import { getAttribute, addClasses, htmlDecode, ensureUniqueId, createDeprecationWarning } from '../utils';
import { getLogger } from '../logger';
import type { Runtime } from '../runtime';
@@ -42,6 +42,12 @@ export function make_PyButton(runtime: Runtime) {
}
async connectedCallback() {
const deprecationMessage = (
'<p>The element &lt;py-button&gt; is deprecated, create a function with your ' +
'inline code and use &lt;button py-click="function()" class="py-button"&gt; instead.</p>'
)
createDeprecationWarning(deprecationMessage, "py-button")
ensureUniqueId(this);
this.code = htmlDecode(this.innerHTML) || '';
this.mount_name = this.id.split('-').join('_');

View File

@@ -1,4 +1,4 @@
import { getAttribute, addClasses, htmlDecode, ensureUniqueId } from '../utils';
import { getAttribute, addClasses, htmlDecode, ensureUniqueId, createDeprecationWarning } from '../utils';
import { getLogger } from '../logger';
import type { Runtime } from '../runtime';
@@ -21,6 +21,11 @@ export function make_PyInputBox(runtime: Runtime) {
}
async connectedCallback() {
const deprecationMessage = (
'<p>The element &lt;py-input&gt; is deprecated, ' +
'use &lt;input class="py-input"&gt; instead.</p>'
)
createDeprecationWarning(deprecationMessage, "py-input")
ensureUniqueId(this);
this.code = htmlDecode(this.innerHTML);
this.mount_name = this.id.split('-').join('_');

View File

@@ -1,4 +1,4 @@
import { addClasses, htmlDecode } from '../utils';
import { addClasses, htmlDecode, createDeprecationWarning } from '../utils';
export class PyTitle extends HTMLElement {
widths: string[];
@@ -9,6 +9,10 @@ export class PyTitle extends HTMLElement {
}
connectedCallback() {
const deprecationMessage = (
'<p>The element &lt;py-title&gt; is deprecated, please use an &lt;h1&gt; tag instead.</p>'
)
createDeprecationWarning(deprecationMessage, "py-title")
this.label = htmlDecode(this.innerHTML);
this.mount_name = this.id.split('-').join('_');
this.innerHTML = '';

View File

@@ -293,6 +293,7 @@ input {
border-color: rgba(37, 99, 235, var(--tw-border-opacity));
border-width: 1px;
border-radius: 0.25rem;
cursor: pointer;
}
.py-li-element p {

View File

@@ -111,3 +111,16 @@ export function joinPaths(parts: string[], separator = '/') {
}
return res;
}
export function createDeprecationWarning(msg: string, elementName: string): void {
const banners = document.getElementsByClassName('alert-banner py-warning');
let bannerCount = 0;
for (const banner of banners) {
if (banner.innerHTML.includes(elementName)) {
bannerCount++;
}
}
if (bannerCount == 0) {
_createAlertBanner(msg, "warning");
}
}

View File

@@ -16,3 +16,19 @@ class TestPyButton(PyScriptTest):
assert len(pybox_element) == 2
assert pybox_element[1].get_attribute("class") == "py-box-child"
def test_deprecated_element(self):
self.pyscript_run(
"""
<py-box>
</py-box>
"""
)
banner = self.page.locator(".py-warning")
banner_content = banner.inner_text()
expected = (
"The element <py-box> is deprecated, you should create a div "
'with "py-box" class name instead. For example: <div class="py-box">'
)
assert banner_content == expected

View File

@@ -16,3 +16,44 @@ class TestPyButton(PyScriptTest):
self.page.locator("text=my button").click()
self.page.locator("text=my button").click()
assert self.console.log.lines == [self.PY_COMPLETE, "clicked!", "clicked!"]
def test_deprecated_element(self):
self.pyscript_run(
"""
<py-button label="my button">
import js
def on_click(evt):
js.console.log('clicked!')
</py-button>
"""
)
banner = self.page.locator(".py-warning")
banner_content = banner.inner_text()
expected = (
"The element <py-button> is deprecated, create a function with your "
'inline code and use <button py-click="function()" class="py-button"> instead.'
)
assert banner_content == expected
def test_creates_single_deprecation_banner(self):
self.pyscript_run(
"""
<py-button label="my button">
import js
def on_click(evt):
js.console.log('clicked!')
</py-button>
<py-button label="another button!">
</py-button>
"""
)
banner = self.page.query_selector_all(".py-warning")
assert len(banner) == 1
banner_content = banner[0].inner_text()
expected = (
"The element <py-button> is deprecated, create a function with your "
'inline code and use <button py-click="function()" class="py-button"> instead.'
)
assert banner_content == expected

View File

@@ -20,3 +20,23 @@ class TestPyInputBox(PyScriptTest):
input.press("Enter")
assert self.console.log.lines == [self.PY_COMPLETE, "Hello"]
def test_deprecated_element(self):
self.pyscript_run(
"""
<py-inputbox label="my input">
import js
def on_keypress(evt):
if evt.key == "Enter":
js.console.log(evt.target.value)
</py-inputbox>
"""
)
banner = self.page.locator(".py-warning")
banner_content = banner.inner_text()
expected = (
"The element <py-input> is deprecated, "
'use <input class="py-input"> instead.'
)
assert banner_content == expected

View File

@@ -14,3 +14,17 @@ class TestPyTitle(PyScriptTest):
# py_title will be none
assert py_title
assert py_title.text_content() == "Hello, World!"
def test_deprecated_element(self):
self.pyscript_run(
"""
<py-title>Hello, world!</py-title>
"""
)
banner = self.page.locator(".py-warning")
banner_content = banner.inner_text()
expected = (
"The element <py-title> is deprecated, please use an <h1> tag instead."
)
assert banner_content == expected

View File

@@ -282,7 +282,7 @@ class TestExamples(PyScriptTest):
self.page.locator("py-repl").type("import utils\ndisplay(utils.now())")
self.page.locator("button").click()
# Make sure the output is in the page
self.page.wait_for_selector("#output")
self.page.wait_for_selector("#my-repl-1-1")
# utils.now returns current date time
content = self.page.content()
pattern = "\\d+/\\d+/\\d+, \\d+:\\d+:\\d+" # e.g. 08/09/2022 15:57:32

View File

@@ -11,6 +11,11 @@ describe('PyButton', () => {
let instance;
beforeEach(() => {
instance = new PyButton();
// Remove all the alert banners created when calling `connectedCallback`
const banners = document.getElementsByClassName("alert-banner")
for (const banner of banners) {
banner.remove()
}
});
it('should get the Button to just instantiate', async () => {
@@ -65,4 +70,19 @@ describe('PyButton', () => {
expect(instanceId).toMatch(/py-(\w+-){1,5}container/);
expect(instance.mount_name).toBe(instanceId.replace('-container', '').split('-').join('_'));
});
it('should create a single deprecation banner', async () => {
document.body.innerHTML = ""
let alertBanners = document.getElementsByClassName('alert-banner');
expect(alertBanners.length).toBe(0);
instance.connectedCallback();
expect(alertBanners.length).toBe(1);
expect(alertBanners[0].innerHTML).toContain("&lt;py-button&gt; is deprecated");
// Calling `connectedCallback` again should not create a new banner
instance.connectedCallback();
alertBanners = document.getElementsByClassName('alert-banner');
expect(alertBanners.length).toBe(1);
})
});