Skip to content

Commit 17cda6f

Browse files
author
dave horner
committed
refactor(examples): update example crates and core logic
- Updated example crates (hello_svelte, reposition, styled, toggle) for improved state management and reset logic. - Modified `src/pane.rs` and example source files for better robustness and compatibility. - Updated Webpack and package configuration in `examples/www` for build improvements. - Improved documentation in `README.md`.
1 parent fbb979b commit 17cda6f

File tree

20 files changed

+668
-127
lines changed

20 files changed

+668
-127
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
12
## Unreleased
3+
- Migrated to Webpack 5 for async WASM and modern JS tooling.
4+
- Dropped stdweb; all browser interop now uses web-sys, wasm-bindgen, and gloo-timers.
5+
- Updated Svelte/Webpack config for compatibility and modern plugin usage.
26

37
## v0.4
48
- (breaking) Changed type of positions from `u32` to `i32` (for pane and global frame). Negative offsets are valid and sometimes necessary.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ features = [
3232

3333
[dev-dependencies]
3434
wasm-bindgen-test = "0.3"
35-
wasm-bindgen-futures = "0.4"
35+
wasm-bindgen-futures = "0.4"
36+

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ The features can be summarized as:
2525

2626
The examples in this crate are hosted online: [div-rs Examples](https://div.paddlers.ch/)
2727

28-
Have a look at the code in example directory. The best way is to clone the repository and run it locally, so you can play around with the code.
28+
Below is an example of the output you can generate with the built-in GIF capture tool:
29+
30+
![Animated Example Output](./div-rs-captured-frames.gif)
31+
32+
Have a look at the code in the example directory. The best way is to clone the repository and run it locally, so you can play around with the code and generate your own GIFs.
2933

3034

3135
## Requirements (2025+)

div-rs-captured-frames.gif

107 KB
Loading

examples/hello_svelte/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
[package]
33
name = "hello_svelte"
44
version = "0.1.0"
5-
authors = ["Jakob Meier <[email protected]>"]
5+
authors = ["Jakob Meier <[email protected]>", "David Horner"]
66
edition = "2018"
77

88
[lib]
99
crate-type = ["cdylib", "rlib"]
1010

1111
[dependencies]
1212
div = { path = "../../" }
13+
gloo-timers = "0.3.0"
1314
wasm-bindgen = "0.2"
1415
wasm-bindgen-futures = "0.4"
1516

@@ -22,4 +23,4 @@ features = [
2223
"Window",
2324
"HtmlScriptElement",
2425
"HtmlHeadElement",
25-
]
26+
]

examples/hello_svelte/src/lib.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
use wasm_bindgen::prelude::*;
22

3-
#[wasm_bindgen(start)]
3+
#[wasm_bindgen]
44
pub fn main() {
5-
div::init_to("div-root").unwrap();
65
set_panic_hook();
76

8-
// Create a new pane at offset (100,100) from body
9-
// with size 500px/500px and then create a single
10-
// text node inside it with an external class stored in TODO
7+
// Defensive: check for double initialization
8+
match div::init_to("div-root") {
9+
Ok(_) => {},
10+
Err(e) => {
11+
panic!("[hello_svelte] div::init_to('div-root') failed: {e:?}.\nThis usually means main() was called without a prior reset, or reset did not complete before main().");
12+
}
13+
}
14+
1115
const X: u32 = 0;
1216
const Y: u32 = 0;
1317
const W: u32 = 500;
1418
const H: u32 = 500;
1519
let class = div::JsClass::preregistered("MyComponent")
16-
.expect("JS class Test has not been registered properly");
17-
div::from_js_class(X as i32, Y as i32, W, H, class).unwrap();
20+
.unwrap_or_else(|| panic!("[hello_svelte] Svelte component 'MyComponent' is not registered.\n\nMake sure register_svelte_component('MyComponent', ...) is called in JS before calling main()."));
21+
div::from_js_class(X as i32, Y as i32, W, H, class).expect("[hello_svelte] div::from_js_class failed");
1822

1923
/* Alternative that loads classes from a separate JS file instead of registering in the JS code. */
2024
// let future = async {
@@ -24,6 +28,11 @@ pub fn main() {
2428
// wasm_bindgen_futures::spawn_local(future);
2529
}
2630

31+
#[wasm_bindgen]
32+
pub fn reset() {
33+
div::reset_global_div_state();
34+
}
35+
2736
pub fn set_panic_hook() {
2837
// When the `console_error_panic_hook` feature is enabled, we can call the
2938
// `set_panic_hook` function at least once during initialization, and then

examples/hello_world/src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
#![allow(unused_must_use)]
21
use wasm_bindgen::prelude::*;
32

43
#[wasm_bindgen(start)]
54
pub fn main() {
6-
div::init_to("div-root");
5+
div::init_to("div-root").expect("Init failed");
76

87
// Create a new pane at offset (100,100) from body
98
// with size 500px/500px and then create a single
@@ -13,5 +12,10 @@ pub fn main() {
1312
let w = 500;
1413
let h = 500;
1514
let html = "Hello world";
16-
div::new(x, y, w, h, html);
15+
div::new(x, y, w, h, html).unwrap();
1716
}
17+
18+
#[wasm_bindgen]
19+
pub fn reset() {
20+
div::reset_global_div_state();
21+
}

examples/reposition/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
[package]
33
name = "reposition"
44
version = "0.1.0"
5-
authors = ["Jakob Meier <[email protected]>"]
5+
authors = ["Jakob Meier <[email protected]>", "David Horner"]
66
edition = "2018"
77

88
[lib]
99
crate-type = ["cdylib", "rlib"]
1010

1111

1212
[dependencies]
13+
console_error_panic_hook = "0.1.7"
1314
div = { path = "../../" }
1415
wasm-bindgen = "0.2"
1516

examples/reposition/src/lib.rs

Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use wasm_bindgen::JsCast;
22
use web_sys::window;
33
use wasm_bindgen::prelude::*;
4+
use console_error_panic_hook;
45

56
/**
67
* This example show how
@@ -19,8 +20,47 @@ use wasm_bindgen::prelude::*;
1920
* repositioned and/or resized, it can also change the arrangement of the internal HTML elements.
2021
*/
2122

23+
static mut KEYDOWN_CLOSURE: Option<Closure<dyn FnMut(web_sys::Event)>> = None;
24+
25+
#[wasm_bindgen]
26+
pub fn reset() {
27+
// Remove the keydown event listener if present
28+
let win = match window() {
29+
Some(w) => w,
30+
None => return,
31+
};
32+
unsafe {
33+
if let Some(old_closure) = KEYDOWN_CLOSURE.take() {
34+
let _ = win.remove_event_listener_with_callback("keydown", old_closure.as_ref().unchecked_ref());
35+
// drop(old_closure); // dropped automatically
36+
}
37+
}
38+
// Also reset the Rust global state so example can be re-initialized
39+
div::reset_global_div_state();
40+
41+
// Explicitly clear all children of div-root (DOM cleanup)
42+
if let Some(doc) = web_sys::window().and_then(|w| w.document()) {
43+
if let Some(div_root) = doc.get_element_by_id("div-root") {
44+
while let Some(child) = div_root.first_child() {
45+
let _ = div_root.remove_child(&child);
46+
}
47+
}
48+
}
49+
}
50+
2251
#[wasm_bindgen(start)]
2352
pub fn main() {
53+
// Enable better panic messages
54+
console_error_panic_hook::set_once();
55+
56+
// Remove previous keydown listener if present
57+
let win = window().unwrap();
58+
unsafe {
59+
if let Some(old_closure) = KEYDOWN_CLOSURE.take() {
60+
let _ = win.remove_event_listener_with_callback("keydown", old_closure.as_ref().unchecked_ref());
61+
// drop(old_closure); // dropped automatically
62+
}
63+
}
2464

2565
// Start at position (0,0) with size (350,200)
2666
let mut x = 0;
@@ -52,43 +92,50 @@ pub fn main() {
5292
let _pane_b = div::new(200, 50, 100, 100, html2).unwrap();
5393

5494
// Define control variables for zoom of global area and pane A
55-
let mut f = 1.0;
56-
let mut af = 1.0;
95+
let mut f: f32 = 1.0;
96+
let mut af: f32 = 1.0;
5797

58-
// Listen to keydown events to move and reposition all divs
98+
// Listen to keydown events to move and reposition all divs (with bounds checks)
5999
let closure = Closure::wrap(Box::new(move |event: web_sys::Event| {
60100
let keyboard_event = event.dyn_ref::<web_sys::KeyboardEvent>();
61101
if let Some(e) = keyboard_event {
62102
let key = e.key();
63103
match key.as_str() {
64-
"ArrowUp" => y = y.saturating_sub(10),
65-
"ArrowDown" => y += 10,
66-
"ArrowLeft" => x = x.saturating_sub(10),
67-
"ArrowRight" => x += 10,
68-
"+" => f *= 1.5,
69-
"-" => f /= 1.5,
104+
"ArrowUp" => { y = y.saturating_sub(10); },
105+
"ArrowDown" => { y += 10; },
106+
"ArrowLeft" => { x = x.saturating_sub(10); },
107+
"ArrowRight" => { x += 10; },
108+
"+" => { f *= 1.5; },
109+
"-" => { f /= 1.5; },
70110

71-
"w" => ay = ay.saturating_sub(10),
72-
"a" => ax = ax.saturating_sub(10),
73-
"s" => ay += 10,
74-
"d" => ax += 10,
75-
"1" => af *= 1.5,
76-
"2" => af /= 1.5,
111+
"w" => { ay = ay.saturating_sub(10); },
112+
"a" => { ax = ax.saturating_sub(10); },
113+
"s" => { ay += 10; },
114+
"d" => { ax += 10; },
115+
"1" => { af *= 1.5; },
116+
"2" => { af /= 1.5; },
77117

78118
_ => {
79119
web_sys::console::log_1(&format!("pressed {}", key).into());
80120
return;
81121
}
82122
}
83-
div::reposition(x, y).unwrap();
84-
let w = f * w as f32;
85-
let h = f * h as f32;
86-
div::resize(w as u32, h as u32).unwrap();
123+
// Bounds checks to prevent panics
124+
let safe_x = x.max(0);
125+
let safe_y = y.max(0);
126+
let safe_f = f.max(0.1); // Prevent zero/negative scale
127+
let safe_af = af.max(0.1);
128+
let safe_ax = ax.max(0);
129+
let safe_ay = ay.max(0);
130+
let safe_aw = (safe_af * aw as f32).max(1.0);
131+
let safe_ah = (safe_af * ah as f32).max(1.0);
132+
let safe_w = (safe_f * w as f32).max(1.0);
133+
let safe_h = (safe_f * h as f32).max(1.0);
87134

88-
let aw = af * aw as f32;
89-
let ah = af * ah as f32;
135+
div::reposition(safe_x, safe_y).unwrap();
136+
div::resize(safe_w as u32, safe_h as u32).unwrap();
90137
pane_a
91-
.reposition_and_resize(ax, ay, aw as u32, ah as u32)
138+
.reposition_and_resize(safe_ax, safe_ay, safe_aw as u32, safe_ah as u32)
92139
.unwrap();
93140
// Same as
94141
// pane_a.reposition(ax,ay).unwrap();
@@ -97,9 +144,8 @@ pub fn main() {
97144
}
98145
}) as Box<dyn FnMut(_)>);
99146

100-
window()
101-
.unwrap()
102-
.add_event_listener_with_callback("keydown", closure.as_ref().unchecked_ref())
103-
.unwrap();
104-
closure.forget();
105-
}
147+
win.add_event_listener_with_callback("keydown", closure.as_ref().unchecked_ref()).unwrap();
148+
unsafe {
149+
KEYDOWN_CLOSURE = Some(closure);
150+
}
151+
}

examples/styled/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
[package]
33
name = "styled"
44
version = "0.1.0"
5-
authors = ["Jakob Meier <[email protected]>"]
5+
authors = ["Jakob Meier <[email protected]>", "David Horner"]
66
edition = "2018"
77

88
[lib]

0 commit comments

Comments
 (0)