Use nightly for Rustfmt (#2630)

* add rustfmt.toml, use nightly in CI, update contributing docs

* run `cargo +nightly fmt`
This commit is contained in:
Muhammad Hamza 2022-04-21 23:21:15 +05:00 committed by GitHub
parent 12c9ebb0ea
commit c28a71e78e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
175 changed files with 935 additions and 765 deletions

View File

@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: nightly
override: true override: true
profile: minimal profile: minimal
components: rustfmt components: rustfmt
@ -25,4 +25,5 @@ jobs:
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: fmt command: fmt
toolchain: nightly
args: --all -- --check args: --all -- --check

View File

@ -73,7 +73,7 @@ The following command checks the code using Rustfmt and Clippy:
cargo make lint cargo make lint
``` ```
To automatically fix formatting issues, run `cargo fmt` first. To automatically fix formatting issues, run `cargo +nightly fmt` first.
## Benchmarks ## Benchmarks
@ -107,4 +107,4 @@ Below, you can find some useful guidance and best practices on how to write APIs
The source code of our website ([https://yew.rs](https://yew.rs)) is in the [website directory](website). The source code of our website ([https://yew.rs](https://yew.rs)) is in the [website directory](website).
Most of the times, edits can be done in markdown. Most of the times, edits can be done in markdown.
[website/README.md](website/README.md) has more detailed instructions. [website/README.md](website/README.md) has more detailed instructions.

View File

@ -30,6 +30,7 @@ run_task = { name = ["lint", "lint-release", "tests"], fork = true }
[tasks.lint] [tasks.lint]
category = "Checks" category = "Checks"
description = "Check formatting and run Clippy" description = "Check formatting and run Clippy"
toolchain = "nightly"
run_task = { name = ["lint-flow"], fork = true } run_task = { name = ["lint-flow"], fork = true }
[tasks.tests] [tasks.tests]

View File

@ -1,6 +1,7 @@
pub mod native_worker; pub mod native_worker;
use std::rc::Rc; use std::rc::Rc;
use yew::{html, Component, Context, Html}; use yew::{html, Component, Context, Html};
use yew_agent::{Bridge, Bridged}; use yew_agent::{Bridge, Bridged};

View File

@ -22,10 +22,10 @@ pub struct Worker {
} }
impl yew_agent::Worker for Worker { impl yew_agent::Worker for Worker {
type Reach = Public<Self>;
type Message = Msg;
type Input = Request; type Input = Request;
type Message = Msg;
type Output = Response; type Output = Response;
type Reach = Public<Self>;
fn create(link: WorkerLink<Self>) -> Self { fn create(link: WorkerLink<Self>) -> Self {
let duration = 3; let duration = 3;

View File

@ -1,9 +1,11 @@
use std::iter;
use rand::Rng;
use yew::{html, Html};
use crate::math::{self, Mean, Vector2D, WeightedMean}; use crate::math::{self, Mean, Vector2D, WeightedMean};
use crate::settings::Settings; use crate::settings::Settings;
use crate::simulation::SIZE; use crate::simulation::SIZE;
use rand::Rng;
use std::iter;
use yew::{html, Html};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Boid { pub struct Boid {

View File

@ -92,9 +92,10 @@ impl App {
fn view_settings(&self, link: &Scope<Self>) -> Html { fn view_settings(&self, link: &Scope<Self>) -> Html {
let Self { settings, .. } = self; let Self { settings, .. } = self;
// This helper macro creates a callback which applies the new value to the current settings and sends `Msg::ChangeSettings`. // This helper macro creates a callback which applies the new value to the current settings
// Thanks to this, we don't need to have "ChangeBoids", "ChangeCohesion", etc. messages, // and sends `Msg::ChangeSettings`. Thanks to this, we don't need to have
// but it comes at the cost of cloning the `Settings` struct each time. // "ChangeBoids", "ChangeCohesion", etc. messages, but it comes at the cost of
// cloning the `Settings` struct each time.
macro_rules! settings_callback { macro_rules! settings_callback {
($link:expr, $settings:ident; $key:ident as $ty:ty) => {{ ($link:expr, $settings:ident; $key:ident as $ty:ty) => {{
let settings = $settings.clone(); let settings = $settings.clone();

View File

@ -1,8 +1,9 @@
use gloo::timers::callback::Interval;
use yew::{html, Component, Context, Html, Properties};
use crate::boid::Boid; use crate::boid::Boid;
use crate::math::Vector2D; use crate::math::Vector2D;
use crate::settings::Settings; use crate::settings::Settings;
use gloo::timers::callback::Interval;
use yew::{html, Component, Context, Html, Properties};
pub const SIZE: Vector2D = Vector2D::new(1600.0, 1000.0); pub const SIZE: Vector2D = Vector2D::new(1600.0, 1000.0);

View File

@ -1,6 +1,8 @@
use std::cell::Cell; use std::cell::Cell;
use web_sys::HtmlInputElement; use web_sys::HtmlInputElement;
use yew::{events::InputEvent, html, Callback, Component, Context, Html, Properties, TargetCast}; use yew::events::InputEvent;
use yew::{html, Callback, Component, Context, Html, Properties, TargetCast};
thread_local! { thread_local! {
static SLIDER_ID: Cell<usize> = Cell::default(); static SLIDER_ID: Cell<usize> = Cell::default();

View File

@ -3,13 +3,12 @@ mod producer;
mod struct_component_subscriber; mod struct_component_subscriber;
mod subscriber; mod subscriber;
use msg_ctx::MessageProvider;
use producer::Producer; use producer::Producer;
use struct_component_subscriber::StructComponentSubscriber; use struct_component_subscriber::StructComponentSubscriber;
use subscriber::Subscriber; use subscriber::Subscriber;
use yew::prelude::*; use yew::prelude::*;
use msg_ctx::MessageProvider;
#[function_component] #[function_component]
pub fn App() -> Html { pub fn App() -> Html {
html! { html! {

View File

@ -1,7 +1,7 @@
use super::msg_ctx::MessageContext;
use yew::prelude::*; use yew::prelude::*;
use super::msg_ctx::MessageContext;
pub enum Msg { pub enum Msg {
MessageContextUpdated(MessageContext), MessageContextUpdated(MessageContext),
} }

View File

@ -1,7 +1,7 @@
use super::msg_ctx::MessageContext;
use yew::prelude::*; use yew::prelude::*;
use super::msg_ctx::MessageContext;
#[function_component] #[function_component]
pub fn Subscriber() -> Html { pub fn Subscriber() -> Html {
let msg_ctx = use_context::<MessageContext>().unwrap(); let msg_ctx = use_context::<MessageContext>().unwrap();

View File

@ -1,4 +1,5 @@
use gloo::{console, timers::callback::Interval}; use gloo::console;
use gloo::timers::callback::Interval;
use yew::prelude::*; use yew::prelude::*;
pub struct CounterModel { pub struct CounterModel {
@ -17,7 +18,6 @@ pub enum CounterMessage {
impl Component for CounterModel { impl Component for CounterModel {
type Message = CounterMessage; type Message = CounterMessage;
type Properties = CounterProps; type Properties = CounterProps;
fn create(ctx: &Context<Self>) -> Self { fn create(ctx: &Context<Self>) -> Self {

View File

@ -16,7 +16,8 @@ pub enum Msg {
} }
pub struct App { pub struct App {
apps: Slab<(Element, AppHandle<CounterModel>)>, // Contains the spawned apps and their parent div elements apps: Slab<(Element, AppHandle<CounterModel>)>, /* Contains the spawned apps and their
* parent div elements */
apps_container_ref: NodeRef, apps_container_ref: NodeRef,
} }

View File

@ -1,10 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use web_sys::{Event, HtmlInputElement};
use yew::{html, html::TargetCast, Component, Context, Html};
use gloo_file::callbacks::FileReader; use gloo_file::callbacks::FileReader;
use gloo_file::File; use gloo_file::File;
use web_sys::{Event, HtmlInputElement};
use yew::html::TargetCast;
use yew::{html, Component, Context, Html};
type Chunks = bool; type Chunks = bool;

View File

@ -1,12 +1,13 @@
use std::cell::RefCell;
use std::rc::Rc;
use gloo::timers::callback::{Interval, Timeout}; use gloo::timers::callback::{Interval, Timeout};
use std::{cell::RefCell, rc::Rc};
use yew::prelude::*; use yew::prelude::*;
use yew::{function_component, html}; use yew::{function_component, html};
use crate::components::{ use crate::components::chessboard::Chessboard;
chessboard::Chessboard, game_status_board::GameStatusBoard, score_board::ScoreBoard, use crate::components::game_status_board::GameStatusBoard;
}; use crate::components::score_board::ScoreBoard;
use crate::constant::Status; use crate::constant::Status;
use crate::state::{Action, State}; use crate::state::{Action, State};

View File

@ -1,7 +1,8 @@
use crate::constant::Status;
use yew::prelude::*; use yew::prelude::*;
use yew::{function_component, html, Properties}; use yew::{function_component, html, Properties};
use crate::constant::Status;
#[derive(Properties, Clone, PartialEq)] #[derive(Properties, Clone, PartialEq)]
pub struct Props { pub struct Props {
pub status: Status, pub status: Status,

View File

@ -1,8 +1,8 @@
use yew::{function_component, html, Html, Properties}; use yew::{function_component, html, Html, Properties};
use crate::components::{ use crate::components::score_board_best_score::BestScore;
score_board_best_score::BestScore, score_board_logo::Logo, score_board_progress::GameProgress, use crate::components::score_board_logo::Logo;
}; use crate::components::score_board_progress::GameProgress;
#[derive(PartialEq, Properties, Clone)] #[derive(PartialEq, Properties, Clone)]
pub struct Props { pub struct Props {

View File

@ -1,6 +1,7 @@
use std::rc::Rc;
use gloo::storage::{LocalStorage, Storage}; use gloo::storage::{LocalStorage, Storage};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::rc::Rc;
use yew::prelude::*; use yew::prelude::*;
use crate::constant::{CardName, Status, KEY_BEST_SCORE}; use crate::constant::{CardName, Status, KEY_BEST_SCORE};

View File

@ -6,10 +6,12 @@ use yew_router::history::{AnyHistory, History, MemoryHistory};
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::components::nav::Nav; use crate::components::nav::Nav;
use crate::pages::{ use crate::pages::author::Author;
author::Author, author_list::AuthorList, home::Home, page_not_found::PageNotFound, post::Post, use crate::pages::author_list::AuthorList;
post_list::PostList, use crate::pages::home::Home;
}; use crate::pages::page_not_found::PageNotFound;
use crate::pages::post::Post;
use crate::pages::post_list::PostList;
#[derive(Routable, PartialEq, Clone, Debug)] #[derive(Routable, PartialEq, Clone, Debug)]
pub enum Route { pub enum Route {

View File

@ -1,9 +1,12 @@
use std::rc::Rc; use std::rc::Rc;
use crate::{content::Author, generator::Generated, Route};
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::content::Author;
use crate::generator::Generated;
use crate::Route;
#[derive(Clone, Debug, PartialEq, Properties)] #[derive(Clone, Debug, PartialEq, Properties)]
pub struct Props { pub struct Props {
pub seed: u32, pub seed: u32,

View File

@ -1,6 +1,6 @@
use serde::Deserialize;
use serde::Serialize;
use std::ops::Range; use std::ops::Range;
use serde::{Deserialize, Serialize};
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;

View File

@ -1,9 +1,12 @@
use std::rc::Rc; use std::rc::Rc;
use crate::{content::PostMeta, generator::Generated, Route};
use yew::prelude::*; use yew::prelude::*;
use yew_router::components::Link; use yew_router::components::Link;
use crate::content::PostMeta;
use crate::generator::Generated;
use crate::Route;
#[derive(Clone, Debug, PartialEq, Properties)] #[derive(Clone, Debug, PartialEq, Properties)]
pub struct Props { pub struct Props {
pub seed: u32, pub seed: u32,

View File

@ -1,6 +1,9 @@
use lazy_static::lazy_static; use lazy_static::lazy_static;
use lipsum::MarkovChain; use lipsum::MarkovChain;
use rand::{distributions::Bernoulli, rngs::StdRng, seq::IteratorRandom, Rng, SeedableRng}; use rand::distributions::Bernoulli;
use rand::rngs::StdRng;
use rand::seq::IteratorRandom;
use rand::{Rng, SeedableRng};
const KEYWORDS: &str = include_str!("../data/keywords.txt"); const KEYWORDS: &str = include_str!("../data/keywords.txt");
const SYLLABLES: &str = include_str!("../data/syllables.txt"); const SYLLABLES: &str = include_str!("../data/syllables.txt");

View File

@ -1,7 +1,9 @@
use crate::components::author_card::AuthorState;
use crate::{content, generator::Generated};
use yew::prelude::*; use yew::prelude::*;
use crate::components::author_card::AuthorState;
use crate::content;
use crate::generator::Generated;
#[derive(Clone, Debug, Eq, PartialEq, Properties)] #[derive(Clone, Debug, Eq, PartialEq, Properties)]
pub struct Props { pub struct Props {
pub seed: u32, pub seed: u32,

View File

@ -1,7 +1,9 @@
use crate::components::{author_card::AuthorCard, progress_delay::ProgressDelay};
use rand::{distributions, Rng}; use rand::{distributions, Rng};
use yew::prelude::*; use yew::prelude::*;
use crate::components::author_card::AuthorCard;
use crate::components::progress_delay::ProgressDelay;
/// Amount of milliseconds to wait before showing the next set of authors. /// Amount of milliseconds to wait before showing the next set of authors.
const CAROUSEL_DELAY_MS: u32 = 15000; const CAROUSEL_DELAY_MS: u32 = 15000;

View File

@ -1,10 +1,12 @@
use std::rc::Rc; use std::rc::Rc;
use crate::{content, generator::Generated, Route};
use content::PostPart; use content::PostPart;
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::generator::Generated;
use crate::{content, Route};
#[derive(Clone, Debug, Eq, PartialEq, Properties)] #[derive(Clone, Debug, Eq, PartialEq, Properties)]
pub struct Props { pub struct Props {
pub seed: u32, pub seed: u32,

View File

@ -1,9 +1,10 @@
use crate::components::pagination::PageQuery;
use crate::components::{pagination::Pagination, post_card::PostCard};
use crate::Route;
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::components::pagination::{PageQuery, Pagination};
use crate::components::post_card::PostCard;
use crate::Route;
const ITEMS_PER_PAGE: u32 = 10; const ITEMS_PER_PAGE: u32 = 10;
const TOTAL_PAGES: u32 = u32::MAX / ITEMS_PER_PAGE; const TOTAL_PAGES: u32 = u32::MAX / ITEMS_PER_PAGE;

View File

@ -1,9 +1,10 @@
use crate::hooks::use_bool_toggle::use_bool_toggle;
use crate::state::Entry as Item;
use web_sys::{HtmlInputElement, MouseEvent}; use web_sys::{HtmlInputElement, MouseEvent};
use yew::events::{Event, FocusEvent, KeyboardEvent}; use yew::events::{Event, FocusEvent, KeyboardEvent};
use yew::prelude::*; use yew::prelude::*;
use crate::hooks::use_bool_toggle::use_bool_toggle;
use crate::state::Entry as Item;
#[derive(PartialEq, Properties, Clone)] #[derive(PartialEq, Properties, Clone)]
pub struct EntryProps { pub struct EntryProps {
pub entry: Item, pub entry: Item,

View File

@ -1,6 +1,7 @@
use crate::state::Filter as FilterEnum;
use yew::prelude::*; use yew::prelude::*;
use crate::state::Filter as FilterEnum;
#[derive(PartialEq, Properties)] #[derive(PartialEq, Properties)]
pub struct FilterProps { pub struct FilterProps {
pub filter: FilterEnum, pub filter: FilterEnum,

View File

@ -1,5 +1,6 @@
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use yew::prelude::*; use yew::prelude::*;
#[derive(Clone)] #[derive(Clone)]

View File

@ -7,10 +7,10 @@ mod components;
mod hooks; mod hooks;
mod state; mod state;
use components::{ use components::entry::Entry as EntryItem;
entry::Entry as EntryItem, filter::Filter as FilterItem, header_input::HeaderInput, use components::filter::Filter as FilterItem;
info_footer::InfoFooter, use components::header_input::HeaderInput;
}; use components::info_footer::InfoFooter;
const KEY: &str = "yew.functiontodomvc.self"; const KEY: &str = "yew.functiontodomvc.self";

View File

@ -1,9 +1,8 @@
use std::rc::Rc; use std::rc::Rc;
use yew::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use strum_macros::Display; use strum_macros::{Display, EnumIter};
use strum_macros::EnumIter; use yew::prelude::*;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct State { pub struct State {

View File

@ -1,7 +1,6 @@
use std::{ use std::error::Error;
error::Error, use std::fmt::{self, Debug, Display, Formatter};
fmt::{self, Debug, Display, Formatter},
};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture; use wasm_bindgen_futures::JsFuture;

View File

@ -107,7 +107,7 @@ pub fn render_markdown(src: &str) -> Html {
fn make_tag(t: Tag) -> VTag { fn make_tag(t: Tag) -> VTag {
match t { match t {
Tag::Paragraph => VTag::new("p"), Tag::Paragraph => VTag::new("p"),
Tag::Heading(n, _, _) => VTag::new(n.to_string()), Tag::Heading(n, ..) => VTag::new(n.to_string()),
Tag::BlockQuote => { Tag::BlockQuote => {
let mut el = VTag::new("blockquote"); let mut el = VTag::new("blockquote");
el.add_attribute("class", "blockquote"); el.add_attribute("class", "blockquote");
@ -118,9 +118,9 @@ fn make_tag(t: Tag) -> VTag {
if let CodeBlockKind::Fenced(lang) = code_block_kind { if let CodeBlockKind::Fenced(lang) = code_block_kind {
// Different color schemes may be used for different code blocks, // Different color schemes may be used for different code blocks,
// but a different library (likely js based at the moment) would be necessary to actually provide the // but a different library (likely js based at the moment) would be necessary to
// highlighting support by locating the language classes and applying dom transforms // actually provide the highlighting support by locating the
// on their contents. // language classes and applying dom transforms on their contents.
match lang.as_ref() { match lang.as_ref() {
"html" => el.add_attribute("class", "html-language"), "html" => el.add_attribute("class", "html-language"),
"rust" => el.add_attribute("class", "rust-language"), "rust" => el.add_attribute("class", "rust-language"),
@ -176,7 +176,9 @@ fn make_tag(t: Tag) -> VTag {
} }
el el
} }
Tag::FootnoteDefinition(ref _footnote_id) => VTag::new("span"), // Footnotes are not rendered as anything special Tag::FootnoteDefinition(ref _footnote_id) => VTag::new("span"), // Footnotes are not
// rendered as anything
// special
Tag::Strikethrough => { Tag::Strikethrough => {
let mut el = VTag::new("span"); let mut el = VTag::new("span");
el.add_attribute("class", "text-decoration-strikethrough"); el.add_attribute("class", "text-decoration-strikethrough");

View File

@ -27,7 +27,8 @@ extern "C" {
#[wasm_bindgen(module = "/js/unimp.js")] #[wasm_bindgen(module = "/js/unimp.js")]
extern "C" { extern "C" {
/// This exists so that wasm bindgen copies js/unimp.js to dist/snippets/<bin-name>-<hash>/js/uninp.js /// This exists so that wasm bindgen copies js/unimp.js to
/// dist/snippets/<bin-name>-<hash>/js/uninp.js
#[wasm_bindgen] #[wasm_bindgen]
fn _dummy_fn_so_wasm_bindgen_copies_over_the_file(); fn _dummy_fn_so_wasm_bindgen_copies_over_the_file();
} }

View File

@ -1,8 +1,7 @@
use once_cell::sync::OnceCell;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture; use wasm_bindgen_futures::JsFuture;
use once_cell::sync::OnceCell;
use yew::prelude::*; use yew::prelude::*;
use yew::suspense::{use_future, SuspensionResult}; use yew::suspense::{use_future, SuspensionResult};

View File

@ -178,6 +178,7 @@ impl App {
</> </>
} }
} }
fn button_view(&self, link: &Scope<Self>) -> Html { fn button_view(&self, link: &Scope<Self>) -> Html {
html! { html! {
<> <>
@ -258,6 +259,7 @@ impl App {
</> </>
} }
} }
fn info_view(&self) -> Html { fn info_view(&self) -> Html {
let ids = if self.persons.len() < 20 { let ids = if self.persons.len() < 20 {
self.persons self.persons

View File

@ -1,11 +1,12 @@
use crate::random;
use std::rc::Rc; use std::rc::Rc;
use yew::{html, Component, Context, Html, Properties};
use fake::faker::address::raw::*; use fake::faker::address::raw::*;
use fake::faker::name::raw::*; use fake::faker::name::raw::*;
use fake::locales::*; use fake::locales::*;
use fake::Fake; use fake::Fake;
use yew::{html, Component, Context, Html, Properties};
use crate::random;
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct PersonInfo { pub struct PersonInfo {

View File

@ -1,8 +1,9 @@
use yew::prelude::*;
use super::header::ListHeader; use super::header::ListHeader;
use super::item::ListItem; use super::item::ListItem;
use super::list::List; use super::list::List;
use super::{Hovered, WeakComponentLink}; use super::{Hovered, WeakComponentLink};
use yew::prelude::*;
pub enum Msg { pub enum Msg {
Hover(Hovered), Hover(Hovered),

View File

@ -1,6 +1,7 @@
use yew::prelude::*;
use super::list::{List, Msg as ListMsg}; use super::list::{List, Msg as ListMsg};
use super::{Hovered, WeakComponentLink}; use super::{Hovered, WeakComponentLink};
use yew::prelude::*;
#[derive(Clone, PartialEq, Properties)] #[derive(Clone, PartialEq, Properties)]
pub struct Props { pub struct Props {

View File

@ -1,6 +1,7 @@
use crate::Hovered;
use yew::prelude::*; use yew::prelude::*;
use crate::Hovered;
#[derive(PartialEq, Clone, Properties)] #[derive(PartialEq, Clone, Properties)]
pub struct Props { pub struct Props {
#[prop_or_default] #[prop_or_default]

View File

@ -1,11 +1,13 @@
use crate::header::{ListHeader, Props as HeaderProps};
use crate::item::{ListItem, Props as ItemProps};
use crate::{Hovered, WeakComponentLink};
use std::rc::Rc; use std::rc::Rc;
use yew::html::{ChildrenRenderer, NodeRef}; use yew::html::{ChildrenRenderer, NodeRef};
use yew::prelude::*; use yew::prelude::*;
use yew::virtual_dom::{VChild, VComp}; use yew::virtual_dom::{VChild, VComp};
use crate::header::{ListHeader, Props as HeaderProps};
use crate::item::{ListItem, Props as ItemProps};
use crate::{Hovered, WeakComponentLink};
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum Variants { pub enum Variants {
Item(Rc<<ListItem as Component>::Properties>), Item(Rc<<ListItem as Component>::Properties>),

View File

@ -7,6 +7,7 @@ use std::cell::RefCell;
use std::fmt; use std::fmt;
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use yew::html::{Component, ImplicitClone, Scope}; use yew::html::{Component, ImplicitClone, Scope};
pub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<Scope<COMP>>>>); pub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<Scope<COMP>>>>);

View File

@ -22,6 +22,7 @@ impl App {
.ok() .ok()
.map(|estimate| estimate.score()) .map(|estimate| estimate.score())
} }
fn redout_top_row_text(&self) -> String { fn redout_top_row_text(&self) -> String {
if self.password.is_empty() { if self.password.is_empty() {
return "Provide a password".to_string(); return "Provide a password".to_string();

View File

@ -1,8 +1,5 @@
use wasm_bindgen::JsCast; use wasm_bindgen::{JsCast, UnwrapThrowExt};
use wasm_bindgen::UnwrapThrowExt; use web_sys::{Event, HtmlInputElement, InputEvent};
use web_sys::Event;
use web_sys::HtmlInputElement;
use web_sys::InputEvent;
use yew::prelude::*; use yew::prelude::*;
#[derive(Clone, PartialEq, Properties)] #[derive(Clone, PartialEq, Properties)]

View File

@ -1,7 +1,10 @@
use crate::{content::Author, generator::Generated, Route};
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::content::Author;
use crate::generator::Generated;
use crate::Route;
#[derive(Clone, Debug, PartialEq, Properties)] #[derive(Clone, Debug, PartialEq, Properties)]
pub struct Props { pub struct Props {
pub seed: u64, pub seed: u64,

View File

@ -1,5 +1,4 @@
use serde::Deserialize; use serde::{Deserialize, Serialize};
use serde::Serialize;
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;

View File

@ -1,7 +1,10 @@
use crate::{content::PostMeta, generator::Generated, Route};
use yew::prelude::*; use yew::prelude::*;
use yew_router::components::Link; use yew_router::components::Link;
use crate::content::PostMeta;
use crate::generator::Generated;
use crate::Route;
#[derive(Clone, Debug, PartialEq, Properties)] #[derive(Clone, Debug, PartialEq, Properties)]
pub struct Props { pub struct Props {
pub seed: u64, pub seed: u64,
@ -19,6 +22,7 @@ impl Component for PostCard {
post: PostMeta::generate_from_seed(ctx.props().seed), post: PostMeta::generate_from_seed(ctx.props().seed),
} }
} }
fn changed(&mut self, ctx: &Context<Self>) -> bool { fn changed(&mut self, ctx: &Context<Self>) -> bool {
self.post = PostMeta::generate_from_seed(ctx.props().seed); self.post = PostMeta::generate_from_seed(ctx.props().seed);
true true

View File

@ -1,6 +1,9 @@
use lazy_static::lazy_static; use lazy_static::lazy_static;
use lipsum::MarkovChain; use lipsum::MarkovChain;
use rand::{distributions::Bernoulli, rngs::SmallRng, seq::IteratorRandom, Rng, SeedableRng}; use rand::distributions::Bernoulli;
use rand::rngs::SmallRng;
use rand::seq::IteratorRandom;
use rand::{Rng, SeedableRng};
const KEYWORDS: &str = include_str!("../data/keywords.txt"); const KEYWORDS: &str = include_str!("../data/keywords.txt");
const SYLLABLES: &str = include_str!("../data/syllables.txt"); const SYLLABLES: &str = include_str!("../data/syllables.txt");

View File

@ -5,10 +5,12 @@ mod components;
mod content; mod content;
mod generator; mod generator;
mod pages; mod pages;
use pages::{ use pages::author::Author;
author::Author, author_list::AuthorList, home::Home, page_not_found::PageNotFound, post::Post, use pages::author_list::AuthorList;
post_list::PostList, use pages::home::Home;
}; use pages::page_not_found::PageNotFound;
use pages::post::Post;
use pages::post_list::PostList;
use yew::html::Scope; use yew::html::Scope;
#[derive(Routable, PartialEq, Clone, Debug)] #[derive(Routable, PartialEq, Clone, Debug)]

View File

@ -1,6 +1,8 @@
use crate::{content, generator::Generated};
use yew::prelude::*; use yew::prelude::*;
use crate::content;
use crate::generator::Generated;
#[derive(Clone, Debug, Eq, PartialEq, Properties)] #[derive(Clone, Debug, Eq, PartialEq, Properties)]
pub struct Props { pub struct Props {
pub seed: u64, pub seed: u64,

View File

@ -1,7 +1,9 @@
use crate::components::{author_card::AuthorCard, progress_delay::ProgressDelay};
use rand::{distributions, Rng}; use rand::{distributions, Rng};
use yew::prelude::*; use yew::prelude::*;
use crate::components::author_card::AuthorCard;
use crate::components::progress_delay::ProgressDelay;
/// Amount of milliseconds to wait before showing the next set of authors. /// Amount of milliseconds to wait before showing the next set of authors.
const CAROUSEL_DELAY_MS: u64 = 15000; const CAROUSEL_DELAY_MS: u64 = 15000;

View File

@ -1,8 +1,10 @@
use crate::{content, generator::Generated, Route};
use content::PostPart; use content::PostPart;
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::generator::Generated;
use crate::{content, Route};
#[derive(Clone, Debug, Eq, PartialEq, Properties)] #[derive(Clone, Debug, Eq, PartialEq, Properties)]
pub struct Props { pub struct Props {
pub seed: u64, pub seed: u64,

View File

@ -1,9 +1,10 @@
use crate::components::pagination::PageQuery;
use crate::components::{pagination::Pagination, post_card::PostCard};
use crate::Route;
use yew::prelude::*; use yew::prelude::*;
use yew_router::prelude::*; use yew_router::prelude::*;
use crate::components::pagination::{PageQuery, Pagination};
use crate::components::post_card::PostCard;
use crate::Route;
const ITEMS_PER_PAGE: u64 = 10; const ITEMS_PER_PAGE: u64 = 10;
const TOTAL_PAGES: u64 = u64::MAX / ITEMS_PER_PAGE; const TOTAL_PAGES: u64 = u64::MAX / ITEMS_PER_PAGE;

View File

@ -1,7 +1,8 @@
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use simple_ssr::App; use simple_ssr::App;
use std::path::PathBuf;
use tokio_util::task::LocalPoolHandle; use tokio_util::task::LocalPoolHandle;
use warp::Filter; use warp::Filter;

View File

@ -2,14 +2,13 @@ use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid;
use yew::prelude::*;
use yew::suspense::{Suspension, SuspensionResult};
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio::task::spawn_local; use tokio::task::spawn_local;
use uuid::Uuid;
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_bindgen_futures::spawn_local; use wasm_bindgen_futures::spawn_local;
use yew::prelude::*;
use yew::suspense::{Suspension, SuspensionResult};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct UuidResponse { struct UuidResponse {

View File

@ -1,8 +1,9 @@
use std::collections::HashMap;
use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use function_router::{ServerApp, ServerAppProps}; use function_router::{ServerApp, ServerAppProps};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::path::PathBuf;
use tokio_util::task::LocalPoolHandle; use tokio_util::task::LocalPoolHandle;
use warp::Filter; use warp::Filter;

View File

@ -1,7 +1,5 @@
use gloo::{ use gloo::console::{self, Timer};
console::{self, Timer}, use gloo::timers::callback::{Interval, Timeout};
timers::callback::{Interval, Timeout},
};
use yew::{html, Component, Context, Html}; use yew::{html, Component, Context, Html};
pub enum Msg { pub enum Msg {

View File

@ -2,13 +2,9 @@ use gloo::storage::{LocalStorage, Storage};
use state::{Entry, Filter, State}; use state::{Entry, Filter, State};
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use web_sys::HtmlInputElement as InputElement; use web_sys::HtmlInputElement as InputElement;
use yew::{ use yew::events::{FocusEvent, KeyboardEvent};
classes, use yew::html::Scope;
events::{FocusEvent, KeyboardEvent}, use yew::{classes, html, Classes, Component, Context, Html, NodeRef, TargetCast};
html,
html::Scope,
Classes, Component, Context, Html, NodeRef, TargetCast,
};
mod state; mod state;

View File

@ -16,10 +16,10 @@ pub struct WorkerOutput {
} }
impl yew_agent::Worker for Worker { impl yew_agent::Worker for Worker {
type Reach = Public<Self>;
type Message = ();
type Input = WorkerInput; type Input = WorkerInput;
type Message = ();
type Output = WorkerOutput; type Output = WorkerOutput;
type Reach = Public<Self>;
fn create(link: WorkerLink<Self>) -> Self { fn create(link: WorkerLink<Self>) -> Self {
Self { link } Self { link }

View File

@ -1,10 +1,11 @@
use crate::agent::{Worker, WorkerInput, WorkerOutput};
use std::rc::Rc; use std::rc::Rc;
use web_sys::HtmlInputElement; use web_sys::HtmlInputElement;
use yew::prelude::*; use yew::prelude::*;
use yew_agent::{Bridge, Bridged}; use yew_agent::{Bridge, Bridged};
use crate::agent::{Worker, WorkerInput, WorkerOutput};
pub struct App { pub struct App {
clicker_value: u32, clicker_value: u32,
input_ref: NodeRef, input_ref: NodeRef,

View File

@ -73,8 +73,8 @@ impl Component for App {
request_animation_frame(move |time| link.send_message(Msg::Render(time))) request_animation_frame(move |time| link.send_message(Msg::Render(time)))
}; };
// A reference to the handle must be stored, otherwise it is dropped and the render won't // A reference to the handle must be stored, otherwise it is dropped and the render
// occur. // won't occur.
self._render_loop = Some(handle); self._render_loop = Some(handle);
} }
} }

View File

@ -1,9 +1,10 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use crate::*;
use yew::prelude::*; use yew::prelude::*;
use crate::*;
/// State handle for [`use_bridge`] hook /// State handle for [`use_bridge`] hook
pub struct UseBridgeHandle<T> pub struct UseBridgeHandle<T>
where where

View File

@ -5,12 +5,13 @@
//! properties have been set, the builder moves to the final build step which implements the //! properties have been set, the builder moves to the final build step which implements the
//! `build()` method. //! `build()` method.
use super::generics::{to_arguments, with_param_bounds, GenericArguments};
use super::{DerivePropsInput, PropField};
use proc_macro2::{Ident, Span}; use proc_macro2::{Ident, Span};
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote, ToTokens};
use syn::Attribute; use syn::Attribute;
use super::generics::{to_arguments, with_param_bounds, GenericArguments};
use super::{DerivePropsInput, PropField};
pub struct PropsBuilder<'a> { pub struct PropsBuilder<'a> {
builder_name: &'a Ident, builder_name: &'a Ident,
step_trait: &'a Ident, step_trait: &'a Ident,

View File

@ -1,13 +1,15 @@
use super::generics::GenericArguments;
use super::should_preserve_attr;
use proc_macro2::{Ident, Span};
use quote::{format_ident, quote, quote_spanned};
use std::cmp::{Ord, Ordering, PartialEq, PartialOrd}; use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::convert::TryFrom; use std::convert::TryFrom;
use proc_macro2::{Ident, Span};
use quote::{format_ident, quote, quote_spanned};
use syn::parse::Result; use syn::parse::Result;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{Attribute, Error, Expr, Field, Path, Type, TypePath, Visibility}; use syn::{Attribute, Error, Expr, Field, Path, Type, TypePath, Visibility};
use super::generics::GenericArguments;
use super::should_preserve_attr;
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
enum PropAttr { enum PropAttr {

View File

@ -1,8 +1,9 @@
use proc_macro2::{Ident, Span}; use proc_macro2::{Ident, Span};
use syn::punctuated::Punctuated;
use syn::token::Colon2;
use syn::{ use syn::{
punctuated::Punctuated, token::Colon2, GenericArgument, GenericParam, Generics, Path, GenericArgument, GenericParam, Generics, Path, PathArguments, PathSegment, Token, TraitBound,
PathArguments, PathSegment, Token, TraitBound, TraitBoundModifier, Type, TypeParam, TraitBoundModifier, Type, TypeParam, TypeParamBound, TypePath,
TypeParamBound, TypePath,
}; };
/// Alias for a comma-separated list of `GenericArgument` /// Alias for a comma-separated list of `GenericArgument`
@ -18,7 +19,8 @@ fn first_default_or_const_param_position(generics: &Generics) -> Option<usize> {
} }
/// Converts `GenericParams` into `GenericArguments` and adds `type_ident` as a type arg. /// Converts `GenericParams` into `GenericArguments` and adds `type_ident` as a type arg.
/// `type_ident` is added at the end of the existing type arguments which don't have a default value. /// `type_ident` is added at the end of the existing type arguments which don't have a default
/// value.
pub fn to_arguments(generics: &Generics, type_ident: Ident) -> GenericArguments { pub fn to_arguments(generics: &Generics, type_ident: Ident) -> GenericArguments {
let mut args: GenericArguments = Punctuated::new(); let mut args: GenericArguments = Punctuated::new();
args.extend(generics.params.iter().map(|param| match param { args.extend(generics.params.iter().map(|param| match param {

View File

@ -3,11 +3,12 @@ mod field;
mod generics; mod generics;
mod wrapper; mod wrapper;
use std::convert::TryInto;
use builder::PropsBuilder; use builder::PropsBuilder;
use field::PropField; use field::PropField;
use proc_macro2::{Ident, Span}; use proc_macro2::{Ident, Span};
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote, ToTokens};
use std::convert::TryInto;
use syn::parse::{Parse, ParseStream, Result}; use syn::parse::{Parse, ParseStream, Result};
use syn::{Attribute, DeriveInput, Generics, Visibility}; use syn::{Attribute, DeriveInput, Generics, Visibility};
use wrapper::PropsWrapper; use wrapper::PropsWrapper;
@ -23,10 +24,10 @@ pub struct DerivePropsInput {
/// Some attributes on the original struct are to be preserved and added to the builder struct, /// Some attributes on the original struct are to be preserved and added to the builder struct,
/// in order to avoid warnings (sometimes reported as errors) in the output. /// in order to avoid warnings (sometimes reported as errors) in the output.
fn should_preserve_attr(attr: &Attribute) -> bool { fn should_preserve_attr(attr: &Attribute) -> bool {
// #[cfg(...)]: does not usually appear in macro inputs, but rust-analyzer seems to generate it sometimes. // #[cfg(...)]: does not usually appear in macro inputs, but rust-analyzer seems to generate it
// If not preserved, results in "no-such-field" errors generating the field setter for `build` // sometimes. If not preserved, results in "no-such-field" errors generating
// #[allow(...)]: silences warnings from clippy, such as dead_code etc. // the field setter for `build` #[allow(...)]: silences warnings from clippy, such as
// #[deny(...)]: enable additional warnings from clippy // dead_code etc. #[deny(...)]: enable additional warnings from clippy
let path = &attr.path; let path = &attr.path;
path.is_ident("allow") || path.is_ident("deny") || path.is_ident("cfg") path.is_ident("allow") || path.is_ident("deny") || path.is_ident("cfg")
} }

View File

@ -1,8 +1,9 @@
use super::PropField;
use proc_macro2::Ident; use proc_macro2::Ident;
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use syn::{Attribute, Generics}; use syn::{Attribute, Generics};
use super::PropField;
pub struct PropsWrapper<'a> { pub struct PropsWrapper<'a> {
wrapper_name: &'a Ident, wrapper_name: &'a Ident,
generics: &'a Generics, generics: &'a Generics,

View File

@ -253,8 +253,8 @@ impl FunctionComponent {
let mut block = *block.clone(); let mut block = *block.clone();
let (impl_generics, _ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, _ty_generics, where_clause) = generics.split_for_impl();
// We use _ctx here so if the component does not use any hooks, the usused_vars lint will not // We use _ctx here so if the component does not use any hooks, the usused_vars lint will
// be triggered. // not be triggered.
let ctx_ident = Ident::new("_ctx", Span::mixed_site()); let ctx_ident = Ident::new("_ctx", Span::mixed_site());
let mut body_rewriter = BodyRewriter::new(ctx_ident.clone()); let mut body_rewriter = BodyRewriter::new(ctx_ident.clone());

View File

@ -1,5 +1,6 @@
use proc_macro_error::emit_error;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use proc_macro_error::emit_error;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::visit_mut::VisitMut; use syn::visit_mut::VisitMut;
use syn::{ use syn::{

View File

@ -1,5 +1,6 @@
use proc_macro2::Span;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use proc_macro2::Span;
use syn::visit_mut::{self, VisitMut}; use syn::visit_mut::{self, VisitMut};
use syn::{ use syn::{
GenericArgument, Lifetime, ParenthesizedGenericArguments, Receiver, TypeBareFn, TypeImplTrait, GenericArgument, Lifetime, ParenthesizedGenericArguments, Receiver, TypeBareFn, TypeImplTrait,

View File

@ -1,11 +1,12 @@
use super::{HtmlIterable, HtmlNode, ToNodeIterator};
use crate::PeekValue;
use proc_macro2::Delimiter; use proc_macro2::Delimiter;
use quote::{quote, quote_spanned, ToTokens}; use quote::{quote, quote_spanned, ToTokens};
use syn::buffer::Cursor; use syn::buffer::Cursor;
use syn::parse::{Parse, ParseStream}; use syn::parse::{Parse, ParseStream};
use syn::{braced, token}; use syn::{braced, token};
use super::{HtmlIterable, HtmlNode, ToNodeIterator};
use crate::PeekValue;
pub struct HtmlBlock { pub struct HtmlBlock {
pub content: BlockContent, pub content: BlockContent,
brace: token::Brace, brace: token::Brace,

View File

@ -1,5 +1,3 @@
use super::{HtmlChildrenTree, TagTokens};
use crate::{props::ComponentProps, PeekValue};
use boolinator::Boolinator; use boolinator::Boolinator;
use proc_macro2::Span; use proc_macro2::Span;
use quote::{quote, quote_spanned, ToTokens}; use quote::{quote, quote_spanned, ToTokens};
@ -12,6 +10,10 @@ use syn::{
TypePath, TypePath,
}; };
use super::{HtmlChildrenTree, TagTokens};
use crate::props::ComponentProps;
use crate::PeekValue;
pub struct HtmlComponent { pub struct HtmlComponent {
ty: Type, ty: Type,
props: ComponentProps, props: ComponentProps,

View File

@ -1,13 +1,16 @@
use crate::{non_capitalized_ascii, stringify::Stringify, Peek};
use boolinator::Boolinator;
use proc_macro2::Ident;
use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens};
use std::fmt; use std::fmt;
use boolinator::Boolinator;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens};
use syn::buffer::Cursor; use syn::buffer::Cursor;
use syn::ext::IdentExt; use syn::ext::IdentExt;
use syn::parse::{Parse, ParseStream}; use syn::parse::{Parse, ParseStream};
use syn::{spanned::Spanned, LitStr, Token}; use syn::spanned::Spanned;
use syn::{LitStr, Token};
use crate::stringify::Stringify;
use crate::{non_capitalized_ascii, Peek};
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct HtmlDashedName { pub struct HtmlDashedName {

View File

@ -1,7 +1,3 @@
use super::{HtmlChildrenTree, HtmlDashedName, TagTokens};
use crate::props::{ClassesForm, ElementProps, Prop};
use crate::stringify::{Stringify, Value};
use crate::{non_capitalized_ascii, Peek, PeekValue};
use boolinator::Boolinator; use boolinator::Boolinator;
use proc_macro2::{Delimiter, TokenStream}; use proc_macro2::{Delimiter, TokenStream};
use proc_macro_error::emit_warning; use proc_macro_error::emit_warning;
@ -11,6 +7,11 @@ use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{Block, Expr, Ident, Lit, LitStr, Token}; use syn::{Block, Expr, Ident, Lit, LitStr, Token};
use super::{HtmlChildrenTree, HtmlDashedName, TagTokens};
use crate::props::{ClassesForm, ElementProps, Prop};
use crate::stringify::{Stringify, Value};
use crate::{non_capitalized_ascii, Peek, PeekValue};
pub struct HtmlElement { pub struct HtmlElement {
pub name: TagName, pub name: TagName,
pub props: ElementProps, pub props: ElementProps,
@ -55,7 +56,14 @@ impl Parse for HtmlElement {
match name.to_ascii_lowercase_string().as_str() { match name.to_ascii_lowercase_string().as_str() {
"area" | "base" | "br" | "col" | "embed" | "hr" | "img" | "input" | "link" "area" | "base" | "br" | "col" | "embed" | "hr" | "img" | "input" | "link"
| "meta" | "param" | "source" | "track" | "wbr" => { | "meta" | "param" | "source" | "track" | "wbr" => {
return Err(syn::Error::new_spanned(open.to_spanned(), format!("the tag `<{}>` is a void element and cannot have children (hint: rewrite this as `<{0}/>`)", name))); return Err(syn::Error::new_spanned(
open.to_spanned(),
format!(
"the tag `<{}>` is a void element and cannot have children (hint: \
rewrite this as `<{0}/>`)",
name
),
));
} }
_ => {} _ => {}
} }
@ -665,9 +673,10 @@ impl Parse for HtmlElementClose {
if let TagName::Expr(name) = &name { if let TagName::Expr(name) = &name {
if let Some(expr) = &name.expr { if let Some(expr) = &name.expr {
return Err(syn::Error::new_spanned( return Err(syn::Error::new_spanned(
expr, expr,
"dynamic closing tags must not have a body (hint: replace it with just `</@>`)", "dynamic closing tags must not have a body (hint: replace it with just \
)); `</@>`)",
));
} }
} }

View File

@ -1,5 +1,3 @@
use super::{HtmlRootBraced, ToNodeIterator};
use crate::PeekValue;
use boolinator::Boolinator; use boolinator::Boolinator;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{quote_spanned, ToTokens}; use quote::{quote_spanned, ToTokens};
@ -8,6 +6,9 @@ use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{Expr, Token}; use syn::{Expr, Token};
use super::{HtmlRootBraced, ToNodeIterator};
use crate::PeekValue;
pub struct HtmlIf { pub struct HtmlIf {
if_token: Token![if], if_token: Token![if],
cond: Box<Expr>, cond: Box<Expr>,

View File

@ -1,5 +1,3 @@
use super::ToNodeIterator;
use crate::PeekValue;
use boolinator::Boolinator; use boolinator::Boolinator;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{quote_spanned, ToTokens}; use quote::{quote_spanned, ToTokens};
@ -8,6 +6,9 @@ use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{Expr, Token}; use syn::{Expr, Token};
use super::ToNodeIterator;
use crate::PeekValue;
pub struct HtmlIterable(Expr); pub struct HtmlIterable(Expr);
impl PeekValue<()> for HtmlIterable { impl PeekValue<()> for HtmlIterable {

View File

@ -1,5 +1,3 @@
use super::{html_dashed_name::HtmlDashedName, HtmlChildrenTree, TagTokens};
use crate::{props::Prop, Peek, PeekValue};
use boolinator::Boolinator; use boolinator::Boolinator;
use quote::{quote, quote_spanned, ToTokens}; use quote::{quote, quote_spanned, ToTokens};
use syn::buffer::Cursor; use syn::buffer::Cursor;
@ -7,6 +5,11 @@ use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::Expr; use syn::Expr;
use super::html_dashed_name::HtmlDashedName;
use super::{HtmlChildrenTree, TagTokens};
use crate::props::Prop;
use crate::{Peek, PeekValue};
pub struct HtmlList { pub struct HtmlList {
open: HtmlListOpen, open: HtmlListOpen,
pub children: HtmlChildrenTree, pub children: HtmlChildrenTree,

View File

@ -1,6 +1,3 @@
use super::ToNodeIterator;
use crate::stringify::Stringify;
use crate::PeekValue;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{quote_spanned, ToTokens}; use quote::{quote_spanned, ToTokens};
use syn::buffer::Cursor; use syn::buffer::Cursor;
@ -8,6 +5,10 @@ use syn::parse::{Parse, ParseStream, Result};
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{Expr, Lit}; use syn::{Expr, Lit};
use super::ToNodeIterator;
use crate::stringify::Stringify;
use crate::PeekValue;
pub enum HtmlNode { pub enum HtmlNode {
Literal(Box<Lit>), Literal(Box<Lit>),
Expression(Box<Expr>), Expression(Box<Expr>),

View File

@ -4,11 +4,10 @@
use proc_macro_error::emit_warning; use proc_macro_error::emit_warning;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use super::html_element::{HtmlElement, TagName};
use super::HtmlTree;
use crate::props::{ElementProps, Prop}; use crate::props::{ElementProps, Prop};
use super::html_element::TagName;
use super::{html_element::HtmlElement, HtmlTree};
/// Lints HTML elements to check if they are well formed. If the element is not well-formed, then /// Lints HTML elements to check if they are well formed. If the element is not well-formed, then
/// use `proc-macro-error` (and the `emit_warning!` macro) to produce a warning. At present, these /// use `proc-macro-error` (and the `emit_warning!` macro) to produce a warning. At present, these
/// are only emitted on nightly. /// are only emitted on nightly.
@ -100,7 +99,7 @@ impl Lint for ImgAltLint {
emit_warning!( emit_warning!(
quote::quote! {#tag_name}.span(), quote::quote! {#tag_name}.span(),
"All `<img>` tags should have an `alt` attribute which provides a \ "All `<img>` tags should have an `alt` attribute which provides a \
human-readable description " human-readable description "
) )
} }
} }

View File

@ -1,12 +1,12 @@
use crate::PeekValue;
use proc_macro2::{Delimiter, Ident, Span, TokenStream}; use proc_macro2::{Delimiter, Ident, Span, TokenStream};
use quote::{quote, quote_spanned, ToTokens}; use quote::{quote, quote_spanned, ToTokens};
use syn::buffer::Cursor; use syn::buffer::Cursor;
use syn::ext::IdentExt; use syn::ext::IdentExt;
use syn::parse::{Parse, ParseStream}; use syn::parse::{Parse, ParseStream};
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::Token; use syn::{braced, token, Token};
use syn::{braced, token};
use crate::PeekValue;
mod html_block; mod html_block;
mod html_component; mod html_component;
@ -65,9 +65,9 @@ impl Parse for HtmlTree {
impl HtmlTree { impl HtmlTree {
/// Determine the [`HtmlType`] before actually parsing it. /// Determine the [`HtmlType`] before actually parsing it.
/// Even though this method accepts a [`ParseStream`], it is forked and the original stream is not modified. /// Even though this method accepts a [`ParseStream`], it is forked and the original stream is
/// Once a certain `HtmlType` can be deduced for certain, the function eagerly returns with the appropriate type. /// not modified. Once a certain `HtmlType` can be deduced for certain, the function eagerly
/// If invalid html tag, returns `None`. /// returns with the appropriate type. If invalid html tag, returns `None`.
fn peek_html_type(input: ParseStream) -> Option<HtmlType> { fn peek_html_type(input: ParseStream) -> Option<HtmlType> {
let input = input.fork(); // do not modify original ParseStream let input = input.fork(); // do not modify original ParseStream
@ -151,7 +151,8 @@ impl Parse for HtmlRoot {
let stream: TokenStream = input.parse()?; let stream: TokenStream = input.parse()?;
Err(syn::Error::new_spanned( Err(syn::Error::new_spanned(
stream, stream,
"only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)", "only one root html element is allowed (hint: you can wrap multiple html elements \
in a fragment `<></>`)",
)) ))
} else { } else {
Ok(html_root) Ok(html_root)
@ -189,9 +190,10 @@ impl ToTokens for HtmlRootVNode {
/// This trait represents a type that can be unfolded into multiple html nodes. /// This trait represents a type that can be unfolded into multiple html nodes.
pub trait ToNodeIterator { pub trait ToNodeIterator {
/// Generate a token stream which produces a value that implements IntoIterator<Item=T> where T is inferred by the compiler. /// Generate a token stream which produces a value that implements IntoIterator<Item=T> where T
/// The easiest way to achieve this is to call `.into()` on each element. /// is inferred by the compiler. The easiest way to achieve this is to call `.into()` on
/// If the resulting iterator only ever yields a single item this function should return None instead. /// each element. If the resulting iterator only ever yields a single item this function
/// should return None instead.
fn to_node_iterator_stream(&self) -> Option<TokenStream>; fn to_node_iterator_stream(&self) -> Option<TokenStream>;
} }
@ -234,7 +236,8 @@ impl HtmlChildrenTree {
let Self(children) = self; let Self(children) = self;
if self.only_single_node_children() { if self.only_single_node_children() {
// optimize for the common case where all children are single nodes (only using literal html). // optimize for the common case where all children are single nodes (only using literal
// html).
let children_into = children let children_into = children
.iter() .iter()
.map(|child| quote_spanned! {child.span()=> ::std::convert::Into::into(#child) }); .map(|child| quote_spanned! {child.span()=> ::std::convert::Into::into(#child) });

View File

@ -1,9 +1,7 @@
use proc_macro2::{Span, TokenStream, TokenTree}; use proc_macro2::{Span, TokenStream, TokenTree};
use quote::{quote, ToTokens}; use quote::{quote, ToTokens};
use syn::{ use syn::parse::{ParseStream, Parser};
parse::{ParseStream, Parser}, use syn::Token;
Token,
};
/// Check whether two spans are equal. /// Check whether two spans are equal.
/// The implementation is really silly but I couldn't find another way to do it on stable. /// The implementation is really silly but I couldn't find another way to do it on stable.
@ -60,10 +58,12 @@ impl TagTokens {
let scope_spanned = tag.to_spanned(); let scope_spanned = tag.to_spanned();
let content_parser = |input: ParseStream| { let content_parser = |input: ParseStream| {
parse(input, tag).map_err(|err| { parse(input, tag).map_err(|err| {
// we can't modify the scope span used by `ParseStream`. It just uses the call site by default. // we can't modify the scope span used by `ParseStream`. It just uses the call site
// The scope span is used when an error can't be attributed to a token tree (ex. when the input is empty). // by default. The scope span is used when an error can't be
// We rewrite all spans to point at the tag which at least narrows down the correct location. // attributed to a token tree (ex. when the input is empty).
// It's not ideal, but it'll have to do until `syn` gives us more access. // We rewrite all spans to point at the tag which at least narrows down the correct
// location. It's not ideal, but it'll have to do until `syn` gives
// us more access.
error_replace_span(err, Span::call_site(), &scope_spanned) error_replace_span(err, Span::call_site(), &scope_spanned)
}) })
}; };

View File

@ -1,13 +1,13 @@
use super::{Prop, Props, SpecialProps, CHILDREN_LABEL}; use std::convert::TryFrom;
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{quote, quote_spanned, ToTokens}; use quote::{quote, quote_spanned, ToTokens};
use std::convert::TryFrom; use syn::parse::{Parse, ParseStream};
use syn::{ use syn::spanned::Spanned;
parse::{Parse, ParseStream}, use syn::token::Dot2;
spanned::Spanned, use syn::Expr;
token::Dot2,
Expr, use super::{Prop, Props, SpecialProps, CHILDREN_LABEL};
};
struct BaseExpr { struct BaseExpr {
pub dot2: Dot2, pub dot2: Dot2,

View File

@ -1,9 +1,11 @@
use super::{Prop, Props, SpecialProps};
use lazy_static::lazy_static;
use std::collections::HashSet; use std::collections::HashSet;
use lazy_static::lazy_static;
use syn::parse::{Parse, ParseStream}; use syn::parse::{Parse, ParseStream};
use syn::{Expr, ExprTuple}; use syn::{Expr, ExprTuple};
use super::{Prop, Props, SpecialProps};
pub enum ClassesForm { pub enum ClassesForm {
Tuple(ExprTuple), Tuple(ExprTuple),
Single(Box<Expr>), Single(Box<Expr>),

View File

@ -1,17 +1,14 @@
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::ops::{Deref, DerefMut};
use proc_macro2::{Spacing, TokenTree};
use syn::parse::{Parse, ParseBuffer, ParseStream};
use syn::token::Brace;
use syn::{braced, Block, Expr, ExprBlock, ExprPath, ExprRange, Stmt, Token};
use super::CHILDREN_LABEL; use super::CHILDREN_LABEL;
use crate::html_tree::HtmlDashedName; use crate::html_tree::HtmlDashedName;
use proc_macro2::{Spacing, TokenTree};
use std::{
cmp::Ordering,
convert::TryFrom,
ops::{Deref, DerefMut},
};
use syn::{
braced,
parse::{Parse, ParseBuffer, ParseStream},
token::Brace,
Block, Expr, ExprBlock, ExprPath, ExprRange, Stmt, Token,
};
pub struct Prop { pub struct Prop {
pub label: HtmlDashedName, pub label: HtmlDashedName,
@ -54,7 +51,8 @@ impl Prop {
} else { } else {
return Err(syn::Error::new_spanned( return Err(syn::Error::new_spanned(
expr, expr,
"missing label for property value. If trying to use the shorthand property syntax, only identifiers may be used", "missing label for property value. If trying to use the shorthand property \
syntax, only identifiers may be used",
)); ));
}?; }?;
@ -67,7 +65,11 @@ impl Prop {
let equals = input.parse::<Token![=]>().map_err(|_| { let equals = input.parse::<Token![=]>().map_err(|_| {
syn::Error::new_spanned( syn::Error::new_spanned(
&label, &label,
format!("`{}` doesn't have a value. (hint: set the value to `true` or `false` for boolean attributes)", label), format!(
"`{}` doesn't have a value. (hint: set the value to `true` or `false` for \
boolean attributes)",
label
),
) )
})?; })?;
if input.is_empty() { if input.is_empty() {
@ -100,12 +102,11 @@ fn parse_prop_value(input: &ParseBuffer) -> syn::Result<Expr> {
match &expr { match &expr {
Expr::Lit(_) => Ok(expr), Expr::Lit(_) => Ok(expr),
_ => { _ => Err(syn::Error::new_spanned(
Err(syn::Error::new_spanned( &expr,
&expr, "the property value must be either a literal or enclosed in braces. Consider \
"the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.", adding braces around your expression.",
)) )),
}
} }
} }
} }
@ -120,13 +121,14 @@ fn strip_braces(block: ExprBlock) -> syn::Result<Expr> {
match stmt { match stmt {
Stmt::Expr(expr) => Ok(expr), Stmt::Expr(expr) => Ok(expr),
Stmt::Semi(_expr, semi) => Err(syn::Error::new_spanned( Stmt::Semi(_expr, semi) => Err(syn::Error::new_spanned(
semi, semi,
"only an expression may be assigned as a property. Consider removing this semicolon", "only an expression may be assigned as a property. Consider removing this \
semicolon",
)),
_ => Err(syn::Error::new_spanned(
stmt,
"only an expression may be assigned as a property",
)), )),
_ => Err(syn::Error::new_spanned(
stmt,
"only an expression may be assigned as a property",
))
} }
} }
block => Ok(Expr::Block(block)), block => Ok(Expr::Block(block)),
@ -296,8 +298,8 @@ pub struct SpecialProps {
pub key: Option<Prop>, pub key: Option<Prop>,
} }
impl SpecialProps { impl SpecialProps {
const REF_LABEL: &'static str = "ref";
const KEY_LABEL: &'static str = "key"; const KEY_LABEL: &'static str = "key";
const REF_LABEL: &'static str = "ref";
fn pop_from(props: &mut SortedPropList) -> syn::Result<Self> { fn pop_from(props: &mut SortedPropList) -> syn::Result<Self> {
let node_ref = props.pop_unique(Self::REF_LABEL)?; let node_ref = props.pop_unique(Self::REF_LABEL)?;

View File

@ -1,15 +1,15 @@
use super::{ComponentProps, Prop, Props, SortedPropList}; use std::convert::TryInto;
use crate::html_tree::HtmlDashedName;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{quote_spanned, ToTokens}; use quote::{quote_spanned, ToTokens};
use std::convert::TryInto; use syn::parse::{Parse, ParseStream};
use syn::{ use syn::punctuated::Punctuated;
parse::{Parse, ParseStream}, use syn::spanned::Spanned;
punctuated::Punctuated, use syn::token::Brace;
spanned::Spanned, use syn::{Expr, Token, TypePath};
token::Brace,
Expr, Token, TypePath, use super::{ComponentProps, Prop, Props, SortedPropList};
}; use crate::html_tree::HtmlDashedName;
/// Pop from `Punctuated` without leaving it in a state where it has trailing punctuation. /// Pop from `Punctuated` without leaving it in a state where it has trailing punctuation.
fn pop_last_punctuated<T, P>(punctuated: &mut Punctuated<T, P>) -> Option<T> { fn pop_last_punctuated<T, P>(punctuated: &mut Punctuated<T, P>) -> Option<T> {
@ -30,7 +30,8 @@ fn is_associated_properties(ty: &TypePath) -> bool {
if let Some(seg) = segments_it.next_back() { if let Some(seg) = segments_it.next_back() {
// ... and we can be reasonably sure that the previous segment is a component ... // ... and we can be reasonably sure that the previous segment is a component ...
if !crate::non_capitalized_ascii(&seg.ident.to_string()) { if !crate::non_capitalized_ascii(&seg.ident.to_string()) {
// ... then we assume that this is an associated type like `Component::Properties` // ... then we assume that this is an associated type like
// `Component::Properties`
return true; return true;
} }
} }
@ -73,7 +74,8 @@ impl Parse for PropsExpr {
fn parse(input: ParseStream) -> syn::Result<Self> { fn parse(input: ParseStream) -> syn::Result<Self> {
let mut ty: TypePath = input.parse()?; let mut ty: TypePath = input.parse()?;
// if the type isn't already qualified (`<x as y>`) and it's an associated type (`MyComp::Properties`) ... // if the type isn't already qualified (`<x as y>`) and it's an associated type
// (`MyComp::Properties`) ...
if ty.qself.is_none() && is_associated_properties(&ty) { if ty.qself.is_none() && is_associated_properties(&ty) {
pop_last_punctuated(&mut ty.path.segments); pop_last_punctuated(&mut ty.path.segments);
// .. transform it into a "qualified-self" type // .. transform it into a "qualified-self" type

View File

@ -11,7 +11,8 @@ fn html_macro() {
#[test] #[test]
#[should_panic( #[should_panic(
expected = "a dynamic tag tried to create a `<br>` tag with children. `<br>` is a void element which can't have any children." expected = "a dynamic tag tried to create a `<br>` tag with children. `<br>` is a void \
element which can't have any children."
)] )]
fn dynamic_tags_catch_void_elements() { fn dynamic_tags_catch_void_elements() {
html! { html! {

View File

@ -7,8 +7,7 @@ use yew::virtual_dom::AttrValue;
use crate::navigator::NavigatorKind; use crate::navigator::NavigatorKind;
use crate::scope_ext::RouterScopeExt; use crate::scope_ext::RouterScopeExt;
use crate::utils; use crate::{utils, Routable};
use crate::Routable;
/// Props for [`Link`] /// Props for [`Link`]
#[derive(Properties, Clone, PartialEq)] #[derive(Properties, Clone, PartialEq)]

View File

@ -1,12 +1,12 @@
//! Hooks to access router state and navigate between pages. //! Hooks to access router state and navigate between pages.
use yew::prelude::*;
use crate::history::*; use crate::history::*;
use crate::navigator::Navigator; use crate::navigator::Navigator;
use crate::routable::Routable; use crate::routable::Routable;
use crate::router::{LocationContext, NavigatorContext}; use crate::router::{LocationContext, NavigatorContext};
use yew::prelude::*;
/// A hook to access the [`Navigator`]. /// A hook to access the [`Navigator`].
#[hook] #[hook]
pub fn use_navigator() -> Option<Navigator> { pub fn use_navigator() -> Option<Navigator> {

View File

@ -4,8 +4,8 @@
//! # Usage //! # Usage
//! //!
//! ```rust //! ```rust
//! use yew::prelude::*;
//! use yew::functional::*; //! use yew::functional::*;
//! use yew::prelude::*;
//! use yew_router::prelude::*; //! use yew_router::prelude::*;
//! //!
//! #[derive(Debug, Clone, Copy, PartialEq, Routable)] //! #[derive(Debug, Clone, Copy, PartialEq, Routable)]
@ -102,7 +102,5 @@ pub mod prelude {
pub use crate::scope_ext::{LocationHandle, NavigatorHandle, RouterScopeExt}; pub use crate::scope_ext::{LocationHandle, NavigatorHandle, RouterScopeExt};
#[doc(no_inline)] #[doc(no_inline)]
pub use crate::Routable; pub use crate::Routable;
pub use crate::{BrowserRouter, HashRouter, Router}; pub use crate::{BrowserRouter, HashRouter, Router, Switch};
pub use crate::Switch;
} }

View File

@ -32,8 +32,8 @@ pub trait Routable: Clone + PartialEq {
/// A special route that accepts any route. /// A special route that accepts any route.
/// ///
/// This can be used with [`History`](gloo::history::History) and [`Location`](gloo::history::Location) /// This can be used with [`History`](gloo::history::History) and
/// when the type of [`Routable`] is unknown. /// [`Location`](gloo::history::Location) when the type of [`Routable`] is unknown.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct AnyRoute { pub struct AnyRoute {
path: String, path: String,

View File

@ -1,11 +1,12 @@
//! Router Component. //! Router Component.
use std::rc::Rc; use std::rc::Rc;
use yew::prelude::*;
use yew::virtual_dom::AttrValue;
use crate::history::{AnyHistory, BrowserHistory, HashHistory, History, Location}; use crate::history::{AnyHistory, BrowserHistory, HashHistory, History, Location};
use crate::navigator::Navigator; use crate::navigator::Navigator;
use crate::utils::{base_url, strip_slash_suffix}; use crate::utils::{base_url, strip_slash_suffix};
use yew::prelude::*;
use yew::virtual_dom::AttrValue;
/// Props for [`Router`]. /// Props for [`Router`].
#[derive(Properties, PartialEq, Clone)] #[derive(Properties, PartialEq, Clone)]

View File

@ -1,11 +1,11 @@
use yew::context::ContextHandle;
use yew::prelude::*;
use crate::history::Location; use crate::history::Location;
use crate::navigator::Navigator; use crate::navigator::Navigator;
use crate::routable::Routable; use crate::routable::Routable;
use crate::router::{LocationContext, NavigatorContext}; use crate::router::{LocationContext, NavigatorContext};
use yew::context::ContextHandle;
use yew::prelude::*;
/// A [`ContextHandle`] for [`add_location_listener`](RouterScopeExt::add_location_listener). /// A [`ContextHandle`] for [`add_location_listener`](RouterScopeExt::add_location_listener).
pub struct LocationHandle { pub struct LocationHandle {
_inner: ContextHandle<LocationContext>, _inner: ContextHandle<LocationContext>,

View File

@ -20,6 +20,7 @@ impl<R> RenderFn<R> {
pub fn new(value: impl Fn(&R) -> Html + 'static) -> Self { pub fn new(value: impl Fn(&R) -> Html + 'static) -> Self {
Self(Rc::new(value)) Self(Rc::new(value))
} }
pub fn render(&self, route: &R) -> Html { pub fn render(&self, route: &R) -> Html {
(self.0)(route) (self.0)(route)
} }

View File

@ -1,4 +1,5 @@
use std::cell::RefCell; use std::cell::RefCell;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
pub(crate) fn strip_slash_suffix(path: &str) -> &str { pub(crate) fn strip_slash_suffix(path: &str) -> &str {
@ -10,8 +11,8 @@ thread_local! {
static BASE_URL: RefCell<Option<String>> = RefCell::new(None); static BASE_URL: RefCell<Option<String>> = RefCell::new(None);
} }
// This exists so we can cache the base url. It costs us a `to_string` call instead of a DOM API call. // This exists so we can cache the base url. It costs us a `to_string` call instead of a DOM API
// Considering base urls are generally short, it *should* be less expensive. // call. Considering base urls are generally short, it *should* be less expensive.
pub fn base_url() -> Option<String> { pub fn base_url() -> Option<String> {
BASE_URL_LOADED.call_once(|| { BASE_URL_LOADED.call_once(|| {
BASE_URL.with(|val| { BASE_URL.with(|val| {

View File

@ -1,6 +1,7 @@
use std::time::Duration;
use gloo::timers::future::sleep; use gloo::timers::future::sleep;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration;
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use yew::functional::function_component; use yew::functional::function_component;
use yew::prelude::*; use yew::prelude::*;

View File

@ -1,6 +1,7 @@
use std::time::Duration;
use gloo::timers::future::sleep; use gloo::timers::future::sleep;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration;
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use yew::functional::function_component; use yew::functional::function_component;
use yew::prelude::*; use yew::prelude::*;

View File

@ -1,6 +1,7 @@
use std::time::Duration;
use gloo::timers::future::sleep; use gloo::timers::future::sleep;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration;
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use yew::functional::function_component; use yew::functional::function_component;
use yew::prelude::*; use yew::prelude::*;

View File

@ -1,6 +1,7 @@
use std::time::Duration;
use gloo::timers::future::sleep; use gloo::timers::future::sleep;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration;
use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
use yew::functional::function_component; use yew::functional::function_component;
use yew::prelude::*; use yew::prelude::*;

Some files were not shown because too many files have changed in this diff Show More