diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md index adfd9f4..b7909d2 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -238,7 +238,7 @@ a `data-*` handle param is statically known or runtime-extracted. 005 Generated module `atoms` exports `Atom` for values that must be addressable, bootstrapped, or synced. Ordinary Rust fields on app/components are not automatically atoms. ### req: codegen/006 -006 `slhx-build` discovers `data-slhx-on` event names from hemplate Surface inputs and emits generated event constants. Event constants are metadata for checked Rust authoring and diagnostics; they do not create a trigger mini-language or new browser runtime semantics. [north_star] +006 `slhx-build` discovers `data-slhx-on` event names from hemplate Surface inputs and emits generated `slhx::EventName` constants. Event constants are metadata for checked Rust authoring and diagnostics; they do not create a trigger mini-language or new browser runtime semantics. [north_star] --- diff --git a/examples/techdemo/src/lib.rs b/examples/techdemo/src/lib.rs index f9dd153..f3fdde5 100644 --- a/examples/techdemo/src/lib.rs +++ b/examples/techdemo/src/lib.rs @@ -74,6 +74,10 @@ mod tests { // req: codegen/006 #[test] fn techdemo_exports_generated_event_constants() { - assert_eq!(ui::issue_lane::events::drop, "drop"); + assert_eq!(ui::issue_lane::events::drop.as_str(), "drop"); + assert!(matches!( + slhx::event(ui::issue_lane::events::drop, "card-1"), + Effect::Emit { name, payload } if name == "drop" && payload == "card-1" + )); } } diff --git a/slhx-build/src/lib.rs b/slhx-build/src/lib.rs index e4832c5..aa90bf9 100644 --- a/slhx-build/src/lib.rs +++ b/slhx-build/src/lib.rs @@ -408,7 +408,7 @@ impl Resources { continue; } out.push_str(&format!( - "{inner}pub const {}: &'static str = {};\n", + "{inner}pub const {}: ::slhx::EventName = ::slhx::EventName::new({});\n", event.ident, rust_str(&event.name) )); @@ -1031,8 +1031,8 @@ mod tests { assert!(generated.contains("pub mod atoms")); assert!(generated.contains("pub const filter")); assert!(generated.contains("pub mod events")); - assert!(generated.contains("pub const click: &'static str = \"click\"")); - assert!(generated.contains("pub const keydown: &'static str = \"keydown\"")); + assert!(generated.contains("pub const click: ::slhx::EventName = ::slhx::EventName::new(\"click\")")); + assert!(generated.contains("pub const keydown: ::slhx::EventName = ::slhx::EventName::new(\"keydown\")")); assert!(generated.contains("pub const new_todo")); assert!(generated.contains("pub mod todo")); assert!(generated.contains("pub const ALL_IDS")); diff --git a/slhx-core/src/lib.rs b/slhx-core/src/lib.rs index e37f983..a16a06f 100644 --- a/slhx-core/src/lib.rs +++ b/slhx-core/src/lib.rs @@ -186,6 +186,41 @@ impl core::fmt::Display for CssClass { } } +/// A generated, checked event token. +/// req: codegen/006 +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct EventName { + name: &'static str, +} + +impl EventName { + pub const fn new(name: &'static str) -> Self { + Self { name } + } + + pub const fn as_str(self) -> &'static str { + self.name + } +} + +impl AsRef for EventName { + fn as_ref(&self) -> &str { + self.name + } +} + +impl From for String { + fn from(event: EventName) -> Self { + event.name.to_string() + } +} + +impl core::fmt::Display for EventName { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(self.name) + } +} + /// A small displayable list of generated CSS class tokens for hemplate `+class`. /// req: style/003 #[derive(Clone, Debug, Eq, PartialEq, Hash)] diff --git a/slhx/src/lib.rs b/slhx/src/lib.rs index 7a8738f..d712105 100644 --- a/slhx/src/lib.rs +++ b/slhx/src/lib.rs @@ -9,7 +9,7 @@ pub use slhx_derive::{app, component, form, handler, surface}; pub mod prelude { pub use slhx_core::{ navigate, push, redirect, replace, Atom, BuildFingerprint, CssClass, CssClasses, Effect, - Form, FormModel, FormValue, Handle, IntoEffect, KeyedSlot, Slot, + EventName, Form, FormModel, FormValue, Handle, IntoEffect, KeyedSlot, Slot, }; pub use slhx_derive::{app, component, form, handler, surface}; }