spaday-regular-layout 0.2.6__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/PKG-INFO +9 -4
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/README.md +7 -2
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/build.mjs +17 -0
- spaday_regular_layout-0.3.0/js/examples/build_pyodide_example.py +50 -0
- spaday_regular_layout-0.3.0/js/examples/pyodide-worker.js +105 -0
- spaday_regular_layout-0.3.0/js/examples/pyodide.html +136 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/package.json +9 -9
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/playwright.config.js +12 -6
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/pnpm-lock.yaml +205 -214
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/src/css/spa.css +76 -27
- spaday_regular_layout-0.3.0/js/src/ts/define-guard.ts +48 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/src/ts/index.ts +6 -1
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/tests/index.spec.js +20 -0
- spaday_regular_layout-0.3.0/js/tests/pyodide.spec.js +48 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/pyproject.toml +3 -3
- spaday_regular_layout-0.3.0/spaday_regular_layout/__init__.py +34 -0
- spaday_regular_layout-0.3.0/spaday_regular_layout/extension/cdn/index.js +21 -0
- spaday_regular_layout-0.3.0/spaday_regular_layout/extension/cdn/index.js.map +7 -0
- spaday_regular_layout-0.3.0/spaday_regular_layout/extension/css/spa.css +1 -0
- spaday_regular_layout-0.3.0/spaday_regular_layout/extension/versions.json +3 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/spaday_regular_layout/tests/test_all.py +13 -1
- spaday_regular_layout-0.3.0/spaday_regular_layout/tests/test_versions.py +18 -0
- spaday_regular_layout-0.2.6/js/src/ts/define-guard.ts +0 -25
- spaday_regular_layout-0.2.6/spaday_regular_layout/__init__.py +0 -18
- spaday_regular_layout-0.2.6/spaday_regular_layout/extension/cdn/index.js +0 -21
- spaday_regular_layout-0.2.6/spaday_regular_layout/extension/cdn/index.js.map +0 -7
- spaday_regular_layout-0.2.6/spaday_regular_layout/extension/css/spa.css +0 -1
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/.gitignore +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/LICENSE +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/.oxfmtrc.json +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/.oxlintrc.json +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/pnpm-workspace.yaml +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/src/css/index.css +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/src/html/index.html +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/src/ts/css.d.ts +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/tools/bundle.mjs +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/tools/css.mjs +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/tools/externals.mjs +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/tools/getarg.mjs +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/tools/html.mjs +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/js/tsconfig.json +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/spaday_regular_layout/components.cem.json +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/spaday_regular_layout/components.py +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/spaday_regular_layout/example.py +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/spaday_regular_layout/extension/css/index.css +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/spaday_regular_layout/extension/css/lorax.css +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/spaday_regular_layout/extension/index.html +0 -0
- {spaday_regular_layout-0.2.6 → spaday_regular_layout-0.3.0}/spaday_regular_layout/tests/test_example.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: spaday-regular-layout
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: regular-layout for spaday
|
|
5
5
|
Project-URL: Repository, https://github.com/1kbgz/spaday-regular-layout
|
|
6
6
|
Project-URL: Homepage, https://github.com/1kbgz/spaday-regular-layout
|
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
17
17
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
18
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
|
-
Requires-Dist: spaday<1.0,>=0.
|
|
20
|
+
Requires-Dist: spaday<1.0,>=0.11.1
|
|
21
21
|
Provides-Extra: develop
|
|
22
22
|
Requires-Dist: build; extra == 'develop'
|
|
23
23
|
Requires-Dist: bump-my-version; extra == 'develop'
|
|
@@ -50,8 +50,8 @@ Description-Content-Type: text/markdown
|
|
|
50
50
|
|
|
51
51
|
<a href="https://github.com/1kbgz/spaday-regular-layout">
|
|
52
52
|
<picture>
|
|
53
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-dark.
|
|
54
|
-
<img alt="spaday-regular-layout logo, a picnic blanket and basket inside a browser window" src="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-light.
|
|
53
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-dark.webp?raw=true">
|
|
54
|
+
<img alt="spaday-regular-layout logo, a picnic blanket and basket inside a browser window" src="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-light.webp?raw=true" width="800">
|
|
55
55
|
</picture>
|
|
56
56
|
</a>
|
|
57
57
|
|
|
@@ -100,6 +100,8 @@ Each frame's content area (`regular-layout-frame::part(container)`) is `display:
|
|
|
100
100
|
|
|
101
101
|
## Run the local example
|
|
102
102
|
|
|
103
|
+
[Run the complete example in your browser](https://1kbgz.github.io/spaday-regular-layout/lite/) — Python runs locally through Pyodide; no install or server required.
|
|
104
|
+
|
|
103
105
|
```bash
|
|
104
106
|
python -m pip install -e ".[examples]"
|
|
105
107
|
python -m spaday_regular_layout.example
|
|
@@ -108,3 +110,6 @@ python -m spaday_regular_layout.example
|
|
|
108
110
|
Open `http://127.0.0.1:8013` to resize and rearrange the [complete three-panel example](spaday_regular_layout/example.py). It
|
|
109
111
|
receives a new server layout every five seconds and persists browser rearrangements back to Python. It passes
|
|
110
112
|
the local package descriptor directly, so it does not install or resolve the integration from GitHub.
|
|
113
|
+
|
|
114
|
+
> [!NOTE]
|
|
115
|
+
> This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<a href="https://github.com/1kbgz/spaday-regular-layout">
|
|
2
2
|
<picture>
|
|
3
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-dark.
|
|
4
|
-
<img alt="spaday-regular-layout logo, a picnic blanket and basket inside a browser window" src="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-light.
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-dark.webp?raw=true">
|
|
4
|
+
<img alt="spaday-regular-layout logo, a picnic blanket and basket inside a browser window" src="https://github.com/1kbgz/spaday-regular-layout/raw/main/docs/img/logo-light.webp?raw=true" width="800">
|
|
5
5
|
</picture>
|
|
6
6
|
</a>
|
|
7
7
|
|
|
@@ -50,6 +50,8 @@ Each frame's content area (`regular-layout-frame::part(container)`) is `display:
|
|
|
50
50
|
|
|
51
51
|
## Run the local example
|
|
52
52
|
|
|
53
|
+
[Run the complete example in your browser](https://1kbgz.github.io/spaday-regular-layout/lite/) — Python runs locally through Pyodide; no install or server required.
|
|
54
|
+
|
|
53
55
|
```bash
|
|
54
56
|
python -m pip install -e ".[examples]"
|
|
55
57
|
python -m spaday_regular_layout.example
|
|
@@ -58,3 +60,6 @@ python -m spaday_regular_layout.example
|
|
|
58
60
|
Open `http://127.0.0.1:8013` to resize and rearrange the [complete three-panel example](spaday_regular_layout/example.py). It
|
|
59
61
|
receives a new server layout every five seconds and persists browser rearrangements back to Python. It passes
|
|
60
62
|
the local package descriptor directly, so it does not install or resolve the integration from GitHub.
|
|
63
|
+
|
|
64
|
+
> [!NOTE]
|
|
65
|
+
> This library was generated using [copier](https://copier.readthedocs.io/en/stable/) from the [Base Python Project Template repository](https://github.com/python-project-templates/base).
|
|
@@ -44,6 +44,23 @@ async function build() {
|
|
|
44
44
|
|
|
45
45
|
await Promise.all(BUNDLES.map(bundle)).catch(() => process.exit(1));
|
|
46
46
|
|
|
47
|
+
// the exact version of every library this package serves, read by the Python package as its
|
|
48
|
+
// ComponentPackage.provides, so spaday can reconcile it with the other packages on a page
|
|
49
|
+
const { dependencies = {} } = JSON.parse(
|
|
50
|
+
fs.readFileSync("package.json", "utf8"),
|
|
51
|
+
);
|
|
52
|
+
const served = Object.fromEntries(
|
|
53
|
+
Object.keys(dependencies).map((name) => [
|
|
54
|
+
name,
|
|
55
|
+
JSON.parse(fs.readFileSync(`node_modules/${name}/package.json`, "utf8"))
|
|
56
|
+
.version,
|
|
57
|
+
]),
|
|
58
|
+
);
|
|
59
|
+
fs.writeFileSync(
|
|
60
|
+
"dist/versions.json",
|
|
61
|
+
`${JSON.stringify(served, null, 2)}\n`,
|
|
62
|
+
);
|
|
63
|
+
|
|
47
64
|
// Copy servable assets to python extension (exclude esm/)
|
|
48
65
|
fs.mkdirSync("../spaday_regular_layout/extension", { recursive: true });
|
|
49
66
|
await cpy("dist/**/*", "../spaday_regular_layout/extension", {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Assemble the static Pyodide example from locally built and downloaded wheels."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import shutil
|
|
5
|
+
import sys
|
|
6
|
+
import zipfile
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def copy_wheel(wheel: Path, output: Path) -> str:
|
|
11
|
+
target = output / "pypi" / wheel.name
|
|
12
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
13
|
+
shutil.copy2(wheel, target)
|
|
14
|
+
return f"pypi/{wheel.name}"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def extract_assets(wheel: Path, package: str, output: Path) -> None:
|
|
18
|
+
prefix = f"{package}/extension/"
|
|
19
|
+
with zipfile.ZipFile(wheel) as archive:
|
|
20
|
+
assets = [name for name in archive.namelist() if name.startswith(prefix) and not name.endswith("/")]
|
|
21
|
+
if not assets:
|
|
22
|
+
raise RuntimeError(f"{wheel.name} contains no browser assets")
|
|
23
|
+
for name in assets:
|
|
24
|
+
target = output / name.removeprefix(prefix)
|
|
25
|
+
target.parent.mkdir(parents=True, exist_ok=True)
|
|
26
|
+
target.write_bytes(archive.read(name))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def one_wheel(directory: Path, distribution: str) -> Path:
|
|
30
|
+
wheels = list(directory.glob(f"{distribution}-*.whl"))
|
|
31
|
+
if len(wheels) != 1:
|
|
32
|
+
raise RuntimeError(f"expected one {distribution} wheel in {directory}, found {len(wheels)}")
|
|
33
|
+
return wheels[0]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def main(output: Path, layout_wheel: Path, dependency_dir: Path) -> None:
|
|
37
|
+
spaday_wheel = one_wheel(dependency_dir, "spaday")
|
|
38
|
+
transports_wheel = one_wheel(dependency_dir, "transports")
|
|
39
|
+
wheels = {
|
|
40
|
+
"layout": copy_wheel(layout_wheel, output),
|
|
41
|
+
"spaday": copy_wheel(spaday_wheel, output),
|
|
42
|
+
"transports": copy_wheel(transports_wheel, output),
|
|
43
|
+
}
|
|
44
|
+
extract_assets(layout_wheel, "spaday_regular_layout", output / "components" / "regular-layout")
|
|
45
|
+
extract_assets(spaday_wheel, "spaday", output / "runtime" / "spaday")
|
|
46
|
+
(output / "wheels.json").write_text(json.dumps(wheels, indent=2) + "\n")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if __name__ == "__main__":
|
|
50
|
+
main(*(Path(value) for value in sys.argv[1:]))
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const PYODIDE_VERSION = "314.0.4";
|
|
2
|
+
let pyodide;
|
|
3
|
+
|
|
4
|
+
const ready = (async () => {
|
|
5
|
+
self.postMessage({ type: "status", message: "Loading Pyodide…" });
|
|
6
|
+
const { loadPyodide } = await import(
|
|
7
|
+
`https://cdn.jsdelivr.net/pyodide/v${PYODIDE_VERSION}/full/pyodide.mjs`
|
|
8
|
+
);
|
|
9
|
+
pyodide = await loadPyodide();
|
|
10
|
+
await pyodide.loadPackage(["micropip", "anyio"]);
|
|
11
|
+
|
|
12
|
+
self.postMessage({ type: "status", message: "Installing example…" });
|
|
13
|
+
const response = await fetch(new URL("./wheels.json", self.location.href));
|
|
14
|
+
if (!response.ok)
|
|
15
|
+
throw new Error(`wheel manifest returned ${response.status}`);
|
|
16
|
+
const wheels = await response.json();
|
|
17
|
+
const urls = Object.fromEntries(
|
|
18
|
+
Object.entries(wheels).map(([name, path]) => [
|
|
19
|
+
name,
|
|
20
|
+
new URL(path, self.location.href).href,
|
|
21
|
+
]),
|
|
22
|
+
);
|
|
23
|
+
pyodide.globals.set("wheels_json", JSON.stringify(urls));
|
|
24
|
+
return pyodide.runPythonAsync(`
|
|
25
|
+
import asyncio
|
|
26
|
+
import json
|
|
27
|
+
import micropip
|
|
28
|
+
|
|
29
|
+
wheels = json.loads(wheels_json)
|
|
30
|
+
await micropip.install([
|
|
31
|
+
wheels["spaday"],
|
|
32
|
+
wheels["transports"],
|
|
33
|
+
"starlette",
|
|
34
|
+
"uvicorn",
|
|
35
|
+
])
|
|
36
|
+
await micropip.install(wheels["layout"], deps=False)
|
|
37
|
+
|
|
38
|
+
from spaday_regular_layout import example
|
|
39
|
+
|
|
40
|
+
connection = "browser"
|
|
41
|
+
|
|
42
|
+
def local_wires(messages):
|
|
43
|
+
return list(messages.get(connection, []))
|
|
44
|
+
|
|
45
|
+
def receive_wire(frame):
|
|
46
|
+
return json.dumps(local_wires(example.server.recv(connection, frame)))
|
|
47
|
+
|
|
48
|
+
def flush_server():
|
|
49
|
+
return json.dumps(local_wires(example.server.flush()))
|
|
50
|
+
|
|
51
|
+
class LocalRequest:
|
|
52
|
+
def __init__(self, body):
|
|
53
|
+
self._body = body
|
|
54
|
+
|
|
55
|
+
async def json(self):
|
|
56
|
+
return self._body
|
|
57
|
+
|
|
58
|
+
async def call_endpoint(body_json):
|
|
59
|
+
response = await example.save_layout(LocalRequest(json.loads(body_json)))
|
|
60
|
+
return json.dumps({
|
|
61
|
+
"status": response.status_code,
|
|
62
|
+
"body": json.loads(bytes(response.body).decode()),
|
|
63
|
+
"wires": local_wires(example.server.flush()),
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
opening = example.server.open(connection, "json")
|
|
67
|
+
asyncio.create_task(example.rotate_layout())
|
|
68
|
+
|
|
69
|
+
json.dumps({
|
|
70
|
+
"tree": example.page.to_node(),
|
|
71
|
+
"style": "",
|
|
72
|
+
"wires": opening,
|
|
73
|
+
})
|
|
74
|
+
`);
|
|
75
|
+
})();
|
|
76
|
+
|
|
77
|
+
let queue = Promise.resolve();
|
|
78
|
+
|
|
79
|
+
async function handle(message) {
|
|
80
|
+
const snapshot = await ready;
|
|
81
|
+
if (message.type === "start") {
|
|
82
|
+
self.postMessage({ type: "snapshot", payload: JSON.parse(snapshot) });
|
|
83
|
+
} else if (message.type === "wire") {
|
|
84
|
+
pyodide.globals.set("wire_frame", message.frame);
|
|
85
|
+
const wires = JSON.parse(pyodide.runPython("receive_wire(wire_frame)"));
|
|
86
|
+
if (wires.length) self.postMessage({ type: "wires", wires });
|
|
87
|
+
} else if (message.type === "flush") {
|
|
88
|
+
const wires = JSON.parse(pyodide.runPython("flush_server()"));
|
|
89
|
+
if (wires.length) self.postMessage({ type: "wires", wires });
|
|
90
|
+
} else if (message.type === "endpoint") {
|
|
91
|
+
pyodide.globals.set("body_json", JSON.stringify(message.body));
|
|
92
|
+
const result = JSON.parse(
|
|
93
|
+
await pyodide.runPythonAsync("await call_endpoint(body_json)"),
|
|
94
|
+
);
|
|
95
|
+
self.postMessage({ type: "endpoint", id: message.id, ...result });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
self.addEventListener("message", (event) => {
|
|
100
|
+
queue = queue
|
|
101
|
+
.then(() => handle(event.data))
|
|
102
|
+
.catch((error) => {
|
|
103
|
+
self.postMessage({ type: "error", message: String(error) });
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>spaday-regular-layout in Pyodide</title>
|
|
7
|
+
<link rel="stylesheet" href="./components/regular-layout/css/index.css" />
|
|
8
|
+
<link rel="stylesheet" href="./components/regular-layout/css/spa.css" />
|
|
9
|
+
<style>
|
|
10
|
+
#pyodide-status {
|
|
11
|
+
position: sticky;
|
|
12
|
+
z-index: 10000;
|
|
13
|
+
top: 0;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
min-height: 3rem;
|
|
16
|
+
padding: 0.75rem 1rem;
|
|
17
|
+
border-bottom: 1px solid #cbd5e1;
|
|
18
|
+
color: #475569;
|
|
19
|
+
background: #fffffff2;
|
|
20
|
+
font:
|
|
21
|
+
14px/1.4 system-ui,
|
|
22
|
+
sans-serif;
|
|
23
|
+
backdrop-filter: blur(12px);
|
|
24
|
+
}
|
|
25
|
+
#pyodide-error {
|
|
26
|
+
margin: 1rem;
|
|
27
|
+
color: #b91c1c;
|
|
28
|
+
white-space: pre-wrap;
|
|
29
|
+
}
|
|
30
|
+
</style>
|
|
31
|
+
</head>
|
|
32
|
+
<body>
|
|
33
|
+
<div id="pyodide-status">Loading Python in the browser…</div>
|
|
34
|
+
<div id="example-root"></div>
|
|
35
|
+
<pre id="pyodide-error" hidden></pre>
|
|
36
|
+
<script type="module">
|
|
37
|
+
import {
|
|
38
|
+
connectStore,
|
|
39
|
+
init,
|
|
40
|
+
mount,
|
|
41
|
+
Store,
|
|
42
|
+
} from "./runtime/spaday/cdn/index.js";
|
|
43
|
+
import "./components/regular-layout/cdn/index.js";
|
|
44
|
+
import * as transports from "./runtime/spaday/transports/cdn/index.js";
|
|
45
|
+
|
|
46
|
+
const status = document.querySelector("#pyodide-status");
|
|
47
|
+
const pendingEndpoints = new Map();
|
|
48
|
+
let nextEndpointId = 0;
|
|
49
|
+
let receiveWires = () => {};
|
|
50
|
+
|
|
51
|
+
function fail(error) {
|
|
52
|
+
status.textContent = "Unable to start";
|
|
53
|
+
const output = document.querySelector("#pyodide-error");
|
|
54
|
+
output.hidden = false;
|
|
55
|
+
output.textContent = String(error);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
await Promise.all([
|
|
60
|
+
init({ module_or_path: "./runtime/spaday/pkg/spaday_bg.wasm" }),
|
|
61
|
+
transports.wasm.default({
|
|
62
|
+
module_or_path:
|
|
63
|
+
"./runtime/spaday/transports/pkg/transports_bg.wasm",
|
|
64
|
+
}),
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
const worker = new Worker("./pyodide-worker.js", { type: "module" });
|
|
68
|
+
const nativeFetch = globalThis.fetch.bind(globalThis);
|
|
69
|
+
globalThis.fetch = async (input, options = {}) => {
|
|
70
|
+
const url = new URL(
|
|
71
|
+
input instanceof Request ? input.url : input,
|
|
72
|
+
location.href,
|
|
73
|
+
);
|
|
74
|
+
if (url.pathname !== "/api/layout")
|
|
75
|
+
return nativeFetch(input, options);
|
|
76
|
+
|
|
77
|
+
const id = ++nextEndpointId;
|
|
78
|
+
const response = new Promise((resolve) => {
|
|
79
|
+
pendingEndpoints.set(id, resolve);
|
|
80
|
+
});
|
|
81
|
+
worker.postMessage({
|
|
82
|
+
type: "endpoint",
|
|
83
|
+
id,
|
|
84
|
+
body: options.body ? JSON.parse(String(options.body)) : null,
|
|
85
|
+
});
|
|
86
|
+
return response;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
worker.addEventListener("message", (event) => {
|
|
90
|
+
if (event.data.type === "status")
|
|
91
|
+
status.textContent = event.data.message;
|
|
92
|
+
if (event.data.type === "error") fail(event.data.message);
|
|
93
|
+
if (event.data.type === "wires") receiveWires(event.data.wires);
|
|
94
|
+
if (event.data.type === "endpoint") {
|
|
95
|
+
receiveWires(event.data.wires);
|
|
96
|
+
const resolve = pendingEndpoints.get(event.data.id);
|
|
97
|
+
if (resolve) {
|
|
98
|
+
pendingEndpoints.delete(event.data.id);
|
|
99
|
+
resolve(
|
|
100
|
+
new Response(JSON.stringify(event.data.body), {
|
|
101
|
+
status: event.data.status,
|
|
102
|
+
headers: { "content-type": "application/json" },
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (event.data.type === "snapshot") {
|
|
108
|
+
const { tree, wires } = event.data.payload;
|
|
109
|
+
const store = new Store();
|
|
110
|
+
const client = new transports.Client();
|
|
111
|
+
const link = connectStore(
|
|
112
|
+
store,
|
|
113
|
+
client,
|
|
114
|
+
(frame) => worker.postMessage({ type: "wire", frame }),
|
|
115
|
+
transports,
|
|
116
|
+
);
|
|
117
|
+
receiveWires = (frames) => {
|
|
118
|
+
for (const frame of frames) link.receive(frame);
|
|
119
|
+
};
|
|
120
|
+
receiveWires(wires);
|
|
121
|
+
mount(document.querySelector("#example-root"), tree, store);
|
|
122
|
+
window.setInterval(
|
|
123
|
+
() => worker.postMessage({ type: "flush" }),
|
|
124
|
+
100,
|
|
125
|
+
);
|
|
126
|
+
status.textContent = "Ready · Python model running in this browser";
|
|
127
|
+
document.documentElement.dataset.ready = "true";
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
worker.postMessage({ type: "start" });
|
|
131
|
+
} catch (error) {
|
|
132
|
+
fail(error);
|
|
133
|
+
}
|
|
134
|
+
</script>
|
|
135
|
+
</body>
|
|
136
|
+
</html>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spaday-regular-layout",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "regular-layout for spaday",
|
|
5
5
|
"repository": "git@github.com:1kbgz/spaday-regular-layout.git",
|
|
6
6
|
"author": "1kbgz <dev@1kbgz.com>",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"build": "npm-run-all build:prod build:types",
|
|
32
32
|
"clean": "rm -rf dist playwright-report ../spaday_regular_layout/extension",
|
|
33
33
|
"dev": "npm-run-all -p start watch",
|
|
34
|
-
"lint": "oxlint . && oxfmt --check \"src/**/*.{js,ts,jsx,tsx,css}\" \"tests/**/*.{js,ts,jsx,tsx}\" \"*.mjs\" \"*.json\"",
|
|
35
|
-
"fix": "oxlint --fix . && oxfmt --write \"src/**/*.{js,ts,jsx,tsx,css}\" \"tests/**/*.{js,ts,jsx,tsx}\" \"*.mjs\" \"*.json\"",
|
|
34
|
+
"lint": "oxlint . && oxfmt --check \"examples/**/*.{js,html}\" \"src/**/*.{js,ts,jsx,tsx,css}\" \"tests/**/*.{js,ts,jsx,tsx}\" \"*.mjs\" \"*.json\"",
|
|
35
|
+
"fix": "oxlint --fix . && oxfmt --write \"examples/**/*.{js,html}\" \"src/**/*.{js,ts,jsx,tsx,css}\" \"tests/**/*.{js,ts,jsx,tsx}\" \"*.mjs\" \"*.json\"",
|
|
36
36
|
"preinstall": "npx only-allow pnpm",
|
|
37
37
|
"prepack": "npm run build",
|
|
38
38
|
"start": "http-server -p 3000 -o examples/",
|
|
@@ -44,15 +44,15 @@
|
|
|
44
44
|
"regular-layout": "=0.6.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@playwright/test": "^1.
|
|
48
|
-
"cpy": "^13.2.
|
|
49
|
-
"esbuild": "^0.28.
|
|
47
|
+
"@playwright/test": "^1.63.0",
|
|
48
|
+
"cpy": "^13.2.3",
|
|
49
|
+
"esbuild": "^0.28.2",
|
|
50
50
|
"http-server": "^14.1.1",
|
|
51
51
|
"lightningcss": "^1.33.0",
|
|
52
|
-
"nodemon": "^3.1.
|
|
52
|
+
"nodemon": "^3.1.14",
|
|
53
53
|
"npm-run-all": "^4.1.5",
|
|
54
|
-
"oxfmt": "^0.
|
|
55
|
-
"oxlint": "^1.
|
|
54
|
+
"oxfmt": "^0.66.0",
|
|
55
|
+
"oxlint": "^1.81.0",
|
|
56
56
|
"typescript": "^7.0.2"
|
|
57
57
|
}
|
|
58
58
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { defineConfig, devices } from "@playwright/test";
|
|
2
2
|
|
|
3
|
+
const pyodideOnly = process.env.SPADAY_REGULAR_LAYOUT_PYODIDE_ONLY === "1";
|
|
4
|
+
|
|
3
5
|
export default defineConfig({
|
|
4
6
|
testDir: "tests",
|
|
5
7
|
fullyParallel: true,
|
|
@@ -28,11 +30,15 @@ export default defineConfig({
|
|
|
28
30
|
reuseExistingServer: !process.env.CI,
|
|
29
31
|
timeout: 120 * 1000,
|
|
30
32
|
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
...(pyodideOnly
|
|
34
|
+
? []
|
|
35
|
+
: [
|
|
36
|
+
{
|
|
37
|
+
command: "python -m spaday_regular_layout.example",
|
|
38
|
+
url: "http://127.0.0.1:8013",
|
|
39
|
+
reuseExistingServer: !process.env.CI,
|
|
40
|
+
timeout: 120 * 1000,
|
|
41
|
+
},
|
|
42
|
+
]),
|
|
37
43
|
],
|
|
38
44
|
});
|