musli_web/yew022.rs
1//! Integration with yew `0.22.x`.
2//!
3//! # Examples
4//!
5//! This example uses [`yew022`]:
6//!
7//! [`yew022`]: crate::yew022
8//!
9//! ```
10//! # extern crate yew022 as yew;
11//! # extern crate web_sys03 as web_sys;
12//! use web_sys::HtmlInputElement;
13//! use yew::prelude::*;
14//! use musli_web::web03::prelude::*;
15//!
16//! mod api {
17//! use musli::{Decode, Encode};
18//! use musli_web::api;
19//!
20//! #[derive(Encode, Decode)]
21//! pub struct HelloRequest<'de> {
22//! pub message: &'de str,
23//! }
24//!
25//! #[derive(Encode, Decode)]
26//! pub struct HelloResponse<'de> {
27//! pub message: &'de str,
28//! }
29//!
30//! #[derive(Encode, Decode)]
31//! pub struct TickEvent<'de> {
32//! pub message: &'de str,
33//! pub tick: u32,
34//! }
35//!
36//! api::define! {
37//! pub type Hello;
38//!
39//! impl Endpoint for Hello {
40//! impl<'de> Request for HelloRequest<'de>;
41//! type Response<'de> = HelloResponse<'de>;
42//! }
43//!
44//! pub type Tick;
45//!
46//! impl Broadcast for Tick {
47//! impl<'de> Event for TickEvent<'de>;
48//! }
49//! }
50//! }
51//!
52//! enum Msg {
53//! Error(ws::Error),
54//! Change(String),
55//! Send,
56//! HelloResponse(Result<ws::Packet<api::Hello>, ws::Error>),
57//! Tick(Result<ws::Packet<api::Tick>, ws::Error>),
58//! }
59//!
60//! struct App {
61//! service: ws::Service,
62//! _listen: ws::Listener,
63//! request: ws::Request,
64//! text: String,
65//! tick: u32,
66//! responses: Vec<String>,
67//! }
68//!
69//! impl Component for App {
70//! type Message = Msg;
71//! type Properties = ();
72//!
73//! fn create(ctx: &Context<Self>) -> Self {
74//! let service = ws::connect(ws::Connect::location("ws"))
75//! .on_error(ctx.link().callback(Msg::Error))
76//! .build();
77//!
78//! service.connect();
79//!
80//! let listen = service.handle().on_broadcast(ctx.link().callback(Msg::Tick));
81//!
82//! Self {
83//! service,
84//! _listen: listen,
85//! request: ws::Request::new(),
86//! text: String::new(),
87//! tick: 0,
88//! responses: Vec::new(),
89//! }
90//! }
91//!
92//! fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
93//! match msg {
94//! Msg::Error(error) => {
95//! tracing::error!("WebSocket error: {:?}", error);
96//! false
97//! }
98//! Msg::Change(text) => {
99//! self.text = text;
100//! true
101//! }
102//! Msg::Send => {
103//! self.request = self
104//! .service
105//! .handle()
106//! .request()
107//! .body(api::HelloRequest {
108//! message: self.text.as_str(),
109//! })
110//! .on_packet(ctx.link().callback(Msg::HelloResponse))
111//! .send();
112//!
113//! self.text.clear();
114//! true
115//! }
116//! Msg::HelloResponse(Err(error)) => {
117//! tracing::error!("Request error: {:?}", error);
118//! false
119//! }
120//! Msg::HelloResponse(Ok(packet)) => {
121//! tracing::debug!("Got response");
122//!
123//! while !packet.is_empty() {
124//! let Ok(response) = packet.decode() else {
125//! break;
126//! };
127//!
128//! self.responses.push(response.message.to_owned());
129//! }
130//!
131//! true
132//! }
133//! Msg::Tick(Err(error)) => {
134//! tracing::error!("Tick error: {error}");
135//! false
136//! }
137//! Msg::Tick(Ok(packet)) => {
138//! tracing::debug!("Got tick");
139//!
140//! if let Ok(tick) = packet.decode_event() {
141//! self.tick = tick.tick;
142//! }
143//!
144//! true
145//! }
146//! }
147//! }
148//!
149//! fn view(&self, ctx: &Context<Self>) -> Html {
150//! let oninput = ctx.link().callback(|e: InputEvent| {
151//! let input = e.target_unchecked_into::<HtmlInputElement>();
152//! Msg::Change(input.value())
153//! });
154//!
155//! let onclick = ctx.link().callback(|_: MouseEvent| {
156//! Msg::Send
157//! });
158//!
159//! html! {
160//! <div class="container">
161//! <input type="text" {oninput} value={self.text.clone()} />
162//! <button {onclick}>{"Send Message"}</button>
163//! {for self.responses.iter().enumerate().map(|(index, response)| html!(<div>{format!("Response #{index}: {response}")}</div>))}
164//! <div>{format!("Global tick: {}", self.tick)}</div>
165//! </div>
166//! }
167//! }
168//! }
169//! ```
170
171use yew022::Callback;
172use yew022::html::ImplicitClone;
173
174use crate::web::{Handle, WebImpl};
175
176impl<H> ImplicitClone for Handle<H>
177where
178 H: WebImpl,
179{
180 #[inline]
181 fn implicit_clone(&self) -> Self {
182 self.clone()
183 }
184}
185
186impl<I> crate::web::Callback<I> for Callback<I>
187where
188 I: 'static,
189{
190 #[inline]
191 fn call(&self, result: I) {
192 self.emit(result);
193 }
194}