Merge pull request #2 from luoxiaozero/feat/leptos-0.5.0-beta

Feat/leptos 0.5.0 beta
This commit is contained in:
luoxiaozero 2023-09-09 22:08:07 +08:00 committed by GitHub
commit f7d8b16483
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 286 additions and 835 deletions

View file

@ -13,10 +13,10 @@ license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
leptos = { version = "0.4.8", features = ["csr"] } leptos = { version = "0.5.0-beta2", features = ["csr"] }
stylers = { git = "https://github.com/abishekatp/stylers", rev = "4bfd2df" } stylers = { git = "https://github.com/abishekatp/stylers", rev = "4bfd2df" }
web-sys = { version = "0.3.62", features = ["DomRect"] } web-sys = { version = "0.3.62", features = ["DomRect"] }
leptos_dom = { version = "0.4.0" } leptos_dom = { version = "0.5.0-beta2" }
wasm-bindgen = "0.2.85" wasm-bindgen = "0.2.85"
icondata = { version = "0.0.7", features = [ icondata = { version = "0.0.7", features = [
"AiCloseOutlined", "AiCloseOutlined",
@ -25,4 +25,4 @@ icondata = { version = "0.0.7", features = [
] } ] }
[workspace] [workspace]
members = ["examples/basic", "gh-pages"] members = ["gh-pages"]

View file

@ -1,16 +0,0 @@
[package]
name = "basic"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
leptos = { version = "0.4.0", features = ["csr"] }
melt-ui = { path = "../../" }
icondata = { version = "0.0.7", features = [
"AiCloseOutlined",
"AiCheckOutlined",
] }
leptos_router = { version = "0.4.0", features = ["csr"] }
regex = "1.8.2"

View file

@ -1,13 +0,0 @@
[build]
target = "index.html"
[watch]
watch = [
"../../src",
"./src"
]
[serve]
address = "127.0.0.1"
port = 6421
open = false

View file

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link data-trunk rel="css" href="./src/assets/css/index.css" />
</head>
<body>
</body>
</html>

View file

@ -1,61 +0,0 @@
use crate::pages::*;
use leptos::*;
use leptos_router::*;
#[component]
pub fn App(cx: Scope) -> impl IntoView {
view! { cx,
<Router>
<Routes>
<Route path="/" view=move |cx| view! {cx,
<Home />
} />
<Route path="/menu" view=move |cx| view! {cx,
<MenuPage />
} />
<Route path="/slider" view=move |cx| view! {cx,
<SliderPage />
} />
<Route path="/components" view=move |cx| view! {cx,
<ComponentsPage />
} >
<Route path="/menu" view=move |cx| view! {cx,
<MenuPage />
} />
<Route path="/slider" view=move |cx| view! {cx,
<SliderPage />
} />
<Route path="/tabbar" view=move |cx| view! {cx,
<MobilePage path="/mobile/tabbar" />
} />
<Route path="/nav-bar" view=move |cx| view! {cx,
<MobilePage path="/mobile/nav-bar" />
} />
<Route path="/input" view=move |cx| view! {cx,
<InputPage />
} />
<Route path="/image" view=move |cx| view! {cx,
<ImagePage />
} />
<Route path="/modal" view=move |cx| view! {cx,
<ModalPage />
} />
<Route path="/button" view=move |cx| view! {cx,
<ButtonPage />
} />
<Route path="/checkbox" view=move |cx| view! {cx,
<CheckboxPage />
} />
</Route>
</Routes>
<Routes base="/mobile".to_string()>
<Route path="/tabbar" view=move |cx| view! {cx,
<TabbarPage />
} />
<Route path="/nav-bar" view=move |cx| view! {cx,
<NavBarPage />
} />
</Routes>
</Router>
}
}

View file

@ -1,16 +0,0 @@
body {
margin: 0;
}
.components-page-box {
display: flex;
}
.components-page-box aside {
width: 260px;
}
.components-page-box main {
flex: 1;
}

View file

@ -1,9 +0,0 @@
mod app;
mod pages;
use app::*;
use leptos::*;
fn main() {
mount_to_body(|cx| view! { cx, <App/> })
}

View file

@ -1,43 +0,0 @@
use leptos::*;
use melt_ui::*;
#[component]
pub fn ButtonPage(cx: Scope) -> impl IntoView {
view! {cx,
<Space>
<Button type_=ButtonType::PRIMARY>
"PRIMARY"
</Button>
<Button type_=ButtonType::SOLID>
"SOLID"
</Button>
<Button type_=ButtonType::TEXT>
"TEXT"
</Button>
<Button type_=ButtonType::LINK>
"LINK"
</Button>
<Button color=ButtonColor::PRIMARY>
"PRIMARY Color"
</Button>
<Button color=ButtonColor::SUCCESS>
"SUCCESS Color"
</Button>
<Button color=ButtonColor::WARNING>
"WARNING Color"
</Button>
<Button color=ButtonColor::ERROR>
"ERROR Color"
</Button>
<Button color=ButtonColor::ERROR icon=icondata::AiIcon::AiCloseOutlined>
"ERROR Color Icon"
</Button>
<Button color=ButtonColor::ERROR icon=icondata::AiIcon::AiCloseOutlined round=true>
</Button>
</Space>
<div style="padding-top: 12px">
<Button style="background: blue;">"style blue"</Button>
<Button style="width: 40px; height: 20px">"size"</Button>
</div>
}
}

View file

@ -1,14 +0,0 @@
use leptos::*;
use melt_ui::*;
#[component]
pub fn CheckboxPage(cx: Scope) -> impl IntoView {
let checked = create_rw_signal(cx, false);
view! {cx,
<div>
<Checkbox checked>
"Click"
</Checkbox>
</div>
}
}

View file

@ -1,52 +0,0 @@
use leptos::*;
use leptos_router::{use_location, use_navigate, Outlet};
use melt_ui::*;
use regex::Regex;
#[component]
pub fn ComponentsPage(cx: Scope) -> impl IntoView {
let loaction = use_location(cx);
let navigate = use_navigate(cx);
let selected = create_rw_signal(cx, String::from(""));
create_effect(cx, move |_| {
let pathname = loaction.pathname.get();
let re = Regex::new(r"^/components/(.+)$").unwrap();
let Some(caps) = re.captures(&pathname) else {
return;
};
let Some(path) = caps.get(1) else {
return;
};
let path = path.as_str().to_string();
selected.set(path);
});
create_effect(cx, move |value| {
let selected = selected.get();
if value.is_some() {
_ = navigate(&format!("/components/{selected}"), Default::default());
}
selected
});
view! {cx,
<div class="components-page-box">
<aside>
<Menu selected>
<MenuItem key="menu" label="menu" />
<MenuItem key="slider" label="slider" />
<MenuItem key="tabbar" label="tabbar" />
<MenuItem key="input" label="input" />
<MenuItem key="image" label="image" />
<MenuItem key="modal" label="madal" />
<MenuItem key="nav-bar" label="nav-bar" />
<MenuItem key="button" label="button" />
<MenuItem key="checkbox" label="checkbox" />
</Menu>
</aside>
<main>
<Outlet />
</main>
</div>
}
}

View file

@ -1,40 +0,0 @@
use leptos::*;
use leptos_router::use_navigate;
use melt_ui::*;
#[component]
pub fn Home(cx: Scope) -> impl IntoView {
let (theme, set_theme) = create_signal(cx, Theme::light());
provide_context(cx, theme);
let (count, set_count) = create_signal(cx, 0.0);
let (button_type, set_button_type) = create_signal(cx, ButtonType::TEXT);
view! { cx,
<Button on:click=move |_| {
let navigate = use_navigate(cx);
_ = navigate("/components/menu", Default::default());
}>
"components"
</Button>
<hr />
<Space>
<Button
on:click=move |_| set_theme.update(move |value| *value = Theme::dark())
type_=button_type
>
"theme"
</Button>
<Button on:click=move |_| set_button_type.update(move |value| *value = ButtonType::PRIMARY)>
"click"
</Button>
<Button
on:click=move |_| set_count.update(move |value| *value += 1.0)
type_=button_type
>
"click"
</Button>
{move || count.get()}
<Progress percentage=count/>
</Space>
}
}

View file

@ -1,12 +0,0 @@
use leptos::*;
use melt_ui::*;
#[component]
pub fn ImagePage(cx: Scope) -> impl IntoView {
view! { cx,
<>
<Image src="https://s3.bmp.ovh/imgs/2021/10/2c3b013418d55659.jpg" width="500px"/>
<Image width="200px" height="200px"/>
</>
}
}

View file

@ -1,14 +0,0 @@
use leptos::*;
use melt_ui::*;
#[component]
pub fn InputPage(cx: Scope) -> impl IntoView {
let value = create_rw_signal(cx, String::from("o"));
view! { cx,
<>
{move || value.get()}
<Input value/>
<Input value type_=InputType::PASSWORD />
</>
}
}

View file

@ -1,16 +0,0 @@
use leptos::*;
use melt_ui::*;
#[component]
pub fn MenuPage(cx: Scope) -> impl IntoView {
let selected = create_rw_signal(cx, String::from("o"));
view! { cx,
<>
{ move || selected.get() }
<Menu selected>
<MenuItem key="a" label="and"/>
<MenuItem key="o" label="or"/>
</Menu>
</>
}
}

View file

@ -1,10 +0,0 @@
use leptos::*;
#[component]
pub fn MobilePage(cx: Scope, path: &'static str) -> impl IntoView {
view! { cx,
<div style="height: 100vh; display: flex; align-items: center; justify-content: center; background: #eff2f5">
<iframe src=path style="width: 360px; height: 640px; background-color: #fff; border: none; border-radius: 16px; border: 1px solid #e1e1e1"/>
</div>
}
}

View file

@ -1,25 +0,0 @@
mod button;
mod checkbox;
mod components;
mod home;
mod image;
mod input;
mod menu;
mod mobile;
mod modal;
mod nav_bar;
mod slider;
mod tabbar;
pub use button::*;
pub use checkbox::*;
pub use components::*;
pub use home::*;
pub use image::*;
pub use input::*;
pub use menu::*;
pub use mobile::*;
pub use modal::*;
pub use nav_bar::*;
pub use slider::*;
pub use tabbar::*;

View file

@ -1,15 +0,0 @@
use leptos::*;
use melt_ui::*;
#[component]
pub fn ModalPage(cx: Scope) -> impl IntoView {
let show = create_rw_signal(cx, false);
view! { cx,
<Button on:click=move |_| show.set(true)>
"open modal"
</Button>
<Modal title="标题" show>
"sd"
</Modal>
}
}

View file

@ -1,24 +0,0 @@
use leptos::*;
use melt_ui::mobile::NavBar;
#[component]
pub fn NavBarPage(cx: Scope) -> impl IntoView {
let click_text = create_rw_signal(cx, String::from("none"));
let click_left = SignalSetter::map(cx, move |_| {
click_text.set("left".to_string())
});
let click_right = SignalSetter::map(cx, move |_| {
click_text.set("right".to_string())
});
view! { cx,
<div style="height: 100vh; background: #f5f5f5">
<NavBar title="Home" left_arrow=true left_text="back" right_text="add" click_left=click_left click_right=click_right/>
<div style="padding-top: 50px">
{ move || click_text.get() }
</div>
</div>
}
}

View file

@ -1,11 +0,0 @@
use leptos::*;
use melt_ui::*;
#[component]
pub fn SliderPage(cx: Scope) -> impl IntoView {
let value = create_rw_signal(cx, 0.0);
view! { cx,
<Slider value/>
}
}

View file

@ -1,23 +0,0 @@
use leptos::*;
use melt_ui::mobile::*;
#[component]
pub fn TabbarPage(cx: Scope) -> impl IntoView {
let selected = create_rw_signal(cx, String::from("o"));
view! { cx,
<div style="height: 100vh; background: #f5f5f5">
{ move || selected.get() }
<Tabbar selected>
<TabbarItem name="a">
"and"
</TabbarItem>
<TabbarItem name="i">
"if"
</TabbarItem>
<TabbarItem name="o" icon=icondata::AiIcon::AiCloseOutlined>
"or"
</TabbarItem>
</Tabbar>
</div>
}
}

View file

@ -6,12 +6,12 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
leptos = { version = "0.4.8", features = ["csr"] } leptos = { version = "0.5.0-beta2", features = ["csr"] }
melt-ui = { path = "../" } melt-ui = { path = "../" }
icondata = { version = "0.0.7", features = [ icondata = { version = "0.0.7", features = [
"AiCloseOutlined", "AiCloseOutlined",
"AiCheckOutlined", "AiCheckOutlined",
] } ] }
leptos_router = { version = "0.4.0", features = ["csr"] } leptos_router = { version = "0.5.0-beta2", features = ["csr"] }
indoc = "2.0.1" indoc = "2.0.1"
regex = "1.8.2" regex = "1.8.2"

3
gh-pages/README.md Normal file
View file

@ -0,0 +1,3 @@
## Used
Run the `trunk serve` command and then open the `http://127.0.0.1:6421/melt-ui` URL

View file

@ -2,7 +2,7 @@
target = "index.html" target = "index.html"
public_url = "/melt-ui/" public_url = "/melt-ui/"
dist = "../docs" dist = "../docs"
release = true # release = true
[watch] [watch]
watch = [ watch = [

View file

@ -3,70 +3,34 @@ use leptos::*;
use leptos_router::*; use leptos_router::*;
#[component] #[component]
pub fn App(cx: Scope) -> impl IntoView { pub fn App() -> impl IntoView {
view! { cx, view! {
<Router base="/melt-ui"> <Router base="/melt-ui">
<Routes base="/melt-ui".to_string() > <Routes base="/melt-ui".to_string() >
<Route path="/" view=move |cx| view! {cx, <Route path="/" view=Home />
<Home /> <Route path="/components" view=ComponentsPage>
} /> <Route path="/menu" view=MenuPage />
<Route path="/menu" view=move |cx| view! {cx, <Route path="/slider" view=SliderPage />
<MenuPage /> <Route path="/tabbar" view=|| view! {
} />
<Route path="/slider" view=move |cx| view! {cx,
<SliderPage />
} />
<Route path="/components" view=move |cx| view! {cx,
<ComponentsPage />
} >
<Route path="/menu" view=move |cx| view! {cx,
<MenuPage />
} />
<Route path="/slider" view=move |cx| view! {cx,
<SliderPage />
} />
<Route path="/tabbar" view=move |cx| view! {cx,
<MobilePage path="/melt-ui?path=/mobile/tabbar" /> <MobilePage path="/melt-ui?path=/mobile/tabbar" />
} /> } />
<Route path="/nav-bar" view=move |cx| view! {cx, <Route path="/nav-bar" view=|| view! {
<MobilePage path="/melt-ui?path=/mobile/nav-bar" /> <MobilePage path="/melt-ui?path=/mobile/nav-bar" />
} /> } />
<Route path="/input" view=move |cx| view! {cx, <Route path="/input" view=InputPage />
<InputPage /> <Route path="/image" view=ImagePage />
} /> <Route path="/modal" view=ModalPage />
<Route path="/image" view=move |cx| view! {cx, <Route path="/button" view=ButtonPage />
<ImagePage /> <Route path="/checkbox" view=CheckboxPage />
} /> <Route path="/toast" view=|| view! {
<Route path="/modal" view=move |cx| view! {cx,
<ModalPage />
} />
<Route path="/button" view=move |cx| view! {cx,
<ButtonPage />
} />
<Route path="/checkbox" view=move |cx| view! {cx,
<CheckboxPage />
} />
<Route path="/toast" view=move |cx| view! {cx,
<MobilePage path="/melt-ui?path=/mobile/toast" /> <MobilePage path="/melt-ui?path=/mobile/toast" />
} /> } />
<Route path="/tabs" view=move |cx| view! {cx, <Route path="/tabs" view=TabsPage />
<TabsPage /> <Route path="/select" view=SelectPage />
} />
<Route path="/select" view=move |cx| view! {cx,
<SelectPage />
} />
</Route> </Route>
</Routes> <Route path="/mobile/tabbar" view=TabbarPage />
<Routes base="/melt-ui/mobile".to_string()> <Route path="/mobile/nav-bar" view=NavBarPage />
<Route path="/tabbar" view=move |cx| view! {cx, <Route path="/mobile/toast" view=ToastPage />
<TabbarPage />
} />
<Route path="/nav-bar" view=move |cx| view! {cx,
<NavBarPage />
} />
<Route path="/toast" view=move |cx| view! {cx,
<ToastPage />
} />
</Routes> </Routes>
</Router> </Router>
} }

View file

@ -3,14 +3,14 @@ use leptos_router::use_navigate;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn SiteHeader(cx: Scope) -> impl IntoView { pub fn SiteHeader() -> impl IntoView {
view! { cx, view! {
<LayoutHeader <LayoutHeader
style="height: 54px; display: flex; align-items: center; justify-content: space-between; padding: 0 20px; border-bottom: 1px solid #efeff6" style="height: 54px; display: flex; align-items: center; justify-content: space-between; padding: 0 20px; border-bottom: 1px solid #efeff6"
> >
<span style="cursor: pointer" on:click=move |_| { <span style="cursor: pointer" on:click=move |_| {
let navigate = use_navigate(cx); let navigate = use_navigate();
_ = navigate("/", Default::default()); navigate("/", Default::default());
}> }>
"Melt UI" "Melt UI"
</span> </span>

View file

@ -6,5 +6,5 @@ use app::*;
use leptos::*; use leptos::*;
fn main() { fn main() {
mount_to_body(|cx| view! { cx, <App/> }) mount_to_body(App)
} }

View file

@ -2,8 +2,8 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn ButtonPage(cx: Scope) -> impl IntoView { pub fn ButtonPage() -> impl IntoView {
view! {cx, view! {
<Space> <Space>
<Button type_=ButtonType::PRIMARY> <Button type_=ButtonType::PRIMARY>
"PRIMARY" "PRIMARY"

View file

@ -2,9 +2,9 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn CheckboxPage(cx: Scope) -> impl IntoView { pub fn CheckboxPage() -> impl IntoView {
let checked = create_rw_signal(cx, false); let checked = create_rw_signal(false);
view! {cx, view! {
<div> <div>
<Checkbox checked> <Checkbox checked>
"Click" "Click"

View file

@ -5,11 +5,11 @@ use melt_ui::*;
use regex::Regex; use regex::Regex;
#[component] #[component]
pub fn ComponentsPage(cx: Scope) -> impl IntoView { pub fn ComponentsPage() -> impl IntoView {
let loaction = use_location(cx); let loaction = use_location();
let navigate = use_navigate(cx); let navigate = use_navigate();
let selected = create_rw_signal(cx, String::from("")); let selected = create_rw_signal(String::from(""));
create_effect(cx, move |_| { create_effect(move |_| {
let pathname = loaction.pathname.get(); let pathname = loaction.pathname.get();
let re = Regex::new(r"^/melt-ui/components/(.+)$").unwrap(); let re = Regex::new(r"^/melt-ui/components/(.+)$").unwrap();
@ -23,14 +23,14 @@ pub fn ComponentsPage(cx: Scope) -> impl IntoView {
selected.set(path); selected.set(path);
}); });
create_effect(cx, move |value| { create_effect(move |value| {
let selected = selected.get(); let selected = selected.get();
if value.is_some() { if value.is_some() {
_ = navigate(&format!("/components/{selected}"), Default::default()); navigate(&format!("/components/{selected}"), Default::default());
} }
selected selected
}); });
view! {cx, view! {
<Layout position=LayoutPosition::ABSOLUTE> <Layout position=LayoutPosition::ABSOLUTE>
<SiteHeader /> <SiteHeader />
<Layout has_sider=true position=LayoutPosition::ABSOLUTE style="top: 54px;"> <Layout has_sider=true position=LayoutPosition::ABSOLUTE style="top: 54px;">

View file

@ -4,23 +4,20 @@ use leptos_router::{use_navigate, use_query_map};
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn Home(cx: Scope) -> impl IntoView { pub fn Home() -> impl IntoView {
let query_map = use_query_map(cx).get(); let query_map = use_query_map().get_untracked();
if let Some(path) = query_map.get("path") { if let Some(path) = query_map.get("path") {
let path = store_value(cx, path.clone()); let navigate = use_navigate();
request_animation_frame(move || { navigate(path, Default::default());
let navigate = use_navigate(cx);
_ = navigate(&path.get_value(), Default::default());
});
} }
view! { cx, view! {
<Layout position=LayoutPosition::ABSOLUTE> <Layout position=LayoutPosition::ABSOLUTE>
<SiteHeader /> <SiteHeader />
<Layout position=LayoutPosition::ABSOLUTE style="top: 54px; display: flex; align-items: center; justify-content: center; flex-direction: column;"> <Layout position=LayoutPosition::ABSOLUTE style="top: 54px; display: flex; align-items: center; justify-content: center; flex-direction: column;">
<p>"A Leptos UI Library"</p> <p>"A Leptos UI Library"</p>
<Button on:click=move |_| { <Button on:click=move |_| {
let navigate = use_navigate(cx); let navigate = use_navigate();
_ = navigate("/components/menu", Default::default()); navigate("/components/menu", Default::default());
}> }>
"Read the docs" "Read the docs"
</Button> </Button>

View file

@ -2,8 +2,8 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn ImagePage(cx: Scope) -> impl IntoView { pub fn ImagePage() -> impl IntoView {
view! { cx, view! {
<> <>
<Image src="https://s3.bmp.ovh/imgs/2021/10/2c3b013418d55659.jpg" width="500px"/> <Image src="https://s3.bmp.ovh/imgs/2021/10/2c3b013418d55659.jpg" width="500px"/>
<Image width="200px" height="200px"/> <Image width="200px" height="200px"/>

View file

@ -2,9 +2,9 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn InputPage(cx: Scope) -> impl IntoView { pub fn InputPage() -> impl IntoView {
let value = create_rw_signal(cx, String::from("o")); let value = create_rw_signal(String::from("o"));
view! { cx, view! {
<> <>
{move || value.get()} {move || value.get()}
<Input value/> <Input value/>

View file

@ -3,9 +3,9 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn MenuPage(cx: Scope) -> impl IntoView { pub fn MenuPage() -> impl IntoView {
let selected = create_rw_signal(cx, String::from("o")); let selected = create_rw_signal(String::from("o"));
view! { cx, view! {
<Card> <Card>
{ move || selected.get() } { move || selected.get() }
<Menu selected> <Menu selected>

View file

@ -1,8 +1,8 @@
use leptos::*; use leptos::*;
#[component] #[component]
pub fn MobilePage(cx: Scope, path: &'static str) -> impl IntoView { pub fn MobilePage(path: &'static str) -> impl IntoView {
view! { cx, view! {
<div style="height: 100vh; display: flex; align-items: center; justify-content: center; background: #eff2f5"> <div style="height: 100vh; display: flex; align-items: center; justify-content: center; background: #eff2f5">
<iframe src=path style="width: 360px; height: 640px; background-color: #fff; border: none; border-radius: 16px; border: 1px solid #e1e1e1"/> <iframe src=path style="width: 360px; height: 640px; background-color: #fff; border: none; border-radius: 16px; border: 1px solid #e1e1e1"/>
</div> </div>

View file

@ -2,9 +2,9 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn ModalPage(cx: Scope) -> impl IntoView { pub fn ModalPage() -> impl IntoView {
let show = create_rw_signal(cx, false); let show = create_rw_signal(false);
view! { cx, view! {
<Button on:click=move |_| show.set(true)> <Button on:click=move |_| show.set(true)>
"open modal" "open modal"
</Button> </Button>

View file

@ -2,18 +2,14 @@ use leptos::*;
use melt_ui::mobile::NavBar; use melt_ui::mobile::NavBar;
#[component] #[component]
pub fn NavBarPage(cx: Scope) -> impl IntoView { pub fn NavBarPage() -> impl IntoView {
let click_text = create_rw_signal(cx, String::from("none")); let click_text = create_rw_signal(String::from("none"));
let click_left = SignalSetter::map(cx, move |_| { let click_left = SignalSetter::map(move |_| click_text.set("left".to_string()));
click_text.set("left".to_string())
});
let click_right = SignalSetter::map(cx, move |_| { let click_right = SignalSetter::map(move |_| click_text.set("right".to_string()));
click_text.set("right".to_string())
});
view! { cx, view! {
<div style="height: 100vh; background: #f5f5f5"> <div style="height: 100vh; background: #f5f5f5">
<NavBar title="Home" left_arrow=true left_text="back" right_text="add" click_left=click_left click_right=click_right/> <NavBar title="Home" left_arrow=true left_text="back" right_text="add" click_left=click_left click_right=click_right/>
<div style="padding-top: 50px"> <div style="padding-top: 50px">

View file

@ -2,14 +2,14 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn SelectPage(cx: Scope) -> impl IntoView { pub fn SelectPage() -> impl IntoView {
let selected_value = create_rw_signal(cx, Some(String::from("apple"))); let selected_value = create_rw_signal(Some(String::from("apple")));
let options = vec![SelectOption { let options = vec![SelectOption {
label: String::from("apple"), label: String::from("apple"),
value: String::from("apple"), value: String::from("apple"),
}]; }];
view! { cx, view! {
<Select value=selected_value options/> <Select value=selected_value options/>
} }
} }

View file

@ -2,10 +2,10 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn SliderPage(cx: Scope) -> impl IntoView { pub fn SliderPage() -> impl IntoView {
let value = create_rw_signal(cx, 0.0); let value = create_rw_signal(0.0);
view! { cx, view! {
<Slider value/> <Slider value/>
} }
} }

View file

@ -2,9 +2,9 @@ use leptos::*;
use melt_ui::mobile::*; use melt_ui::mobile::*;
#[component] #[component]
pub fn TabbarPage(cx: Scope) -> impl IntoView { pub fn TabbarPage() -> impl IntoView {
let selected = create_rw_signal(cx, String::from("o")); let selected = create_rw_signal(String::from("o"));
view! { cx, view! {
<div style="height: 100vh; background: #f5f5f5"> <div style="height: 100vh; background: #f5f5f5">
{ move || selected.get() } { move || selected.get() }
<Tabbar selected> <Tabbar selected>

View file

@ -2,9 +2,9 @@ use leptos::*;
use melt_ui::*; use melt_ui::*;
#[component] #[component]
pub fn TabsPage(cx: Scope) -> impl IntoView { pub fn TabsPage() -> impl IntoView {
let active_key = create_rw_signal(cx, "apple"); let active_key = create_rw_signal("apple");
view! { cx, view! {
<Tabs active_key> <Tabs active_key>
<Tab key="apple" label="Apple"> <Tab key="apple" label="Apple">
"apple" "apple"

View file

@ -1,22 +1,19 @@
use std::time::Duration;
use leptos::*; use leptos::*;
use melt_ui::mobile::*; use melt_ui::mobile::*;
use melt_ui::*; use melt_ui::*;
use std::time::Duration;
#[component] #[component]
pub fn ToastPage(cx: Scope) -> impl IntoView { pub fn ToastPage() -> impl IntoView {
let count = create_rw_signal(cx, 0u32); let count = create_rw_signal(0u32);
let onclick = move |_| { let onclick = move |_| {
show_toast( show_toast(ToastOptions {
cx,
ToastOptions {
message: format!("Hello {}", count.get_untracked()), message: format!("Hello {}", count.get_untracked()),
duration: Duration::from_millis(2000), duration: Duration::from_millis(2000),
}, });
);
count.set(count.get_untracked() + 1); count.set(count.get_untracked() + 1);
}; };
view! {cx, view! {
<div style="margin: 20px"> <div style="margin: 20px">
<Button on:click=onclick>"hi"</Button> <Button on:click=onclick>"hi"</Button>
</div> </div>

View file

@ -35,7 +35,6 @@ impl ButtonColor {
#[component] #[component]
pub fn Button( pub fn Button(
cx: Scope,
#[prop(optional, into)] style: MaybeSignal<String>, #[prop(optional, into)] style: MaybeSignal<String>,
#[prop(optional, into)] type_: MaybeSignal<ButtonType>, #[prop(optional, into)] type_: MaybeSignal<ButtonType>,
#[prop(optional, into)] color: MaybeSignal<ButtonColor>, #[prop(optional, into)] color: MaybeSignal<ButtonColor>,
@ -43,8 +42,8 @@ pub fn Button(
#[prop(optional, into)] icon: Option<Icon>, #[prop(optional, into)] icon: Option<Icon>,
#[prop(optional)] children: Option<ChildrenFn>, #[prop(optional)] children: Option<ChildrenFn>,
) -> impl IntoView { ) -> impl IntoView {
let theme = use_theme(cx, Theme::light); let theme = use_theme(Theme::light);
let css_vars = create_memo(cx, move |_| { let css_vars = create_memo(move |_| {
let mut css_vars = String::new(); let mut css_vars = String::new();
let theme = theme.get(); let theme = theme.get();
let bg_color = color.get().theme_color(&theme); let bg_color = color.get().theme_color(&theme);
@ -69,7 +68,7 @@ pub fn Button(
"" ""
}; };
view! {cx, class=class_name, view! { class=class_name,
<button <button
class:melt-button=true class:melt-button=true
class=("melt-button--text", move || type_.get() == ButtonType::TEXT) class=("melt-button--text", move || type_.get() == ButtonType::TEXT)
@ -81,7 +80,7 @@ pub fn Button(
<Icon icon=icon style=icon_style/> <Icon icon=icon style=icon_style/>
</OptionComp> </OptionComp>
<OptionComp value=children bind:children> <OptionComp value=children bind:children>
{ children(cx) } { children() }
</OptionComp> </OptionComp>
</button> </button>
} }

View file

@ -1,9 +1,7 @@
use crate::theme::ThemeMethod; use crate::theme::ThemeMethod;
#[derive(Clone)] #[derive(Clone)]
pub struct ButtonTheme { pub struct ButtonTheme {}
}
impl ThemeMethod for ButtonTheme { impl ThemeMethod for ButtonTheme {
fn light() -> Self { fn light() -> Self {

View file

@ -23,7 +23,6 @@ pub struct CardFooter {
#[component] #[component]
pub fn Card( pub fn Card(
cx: Scope,
#[prop(optional, into)] title: MaybeSignal<&'static str>, #[prop(optional, into)] title: MaybeSignal<&'static str>,
#[prop(optional)] card_header: Option<CardHeader>, #[prop(optional)] card_header: Option<CardHeader>,
#[prop(optional)] card_header_extra: Option<CardHeaderExtra>, #[prop(optional)] card_header_extra: Option<CardHeaderExtra>,
@ -38,9 +37,9 @@ pub fn Card(
// let footer = card_footer.map_or(None, |v| Some(Rc::new(v))); // let footer = card_footer.map_or(None, |v| Some(Rc::new(v)));
view! { view! {
cx, class=class_name, class=class_name,
<div class="melt-card"> <div class="melt-card">
<If cond=MaybeSignal::derive(cx, move || is_header || !title.get().is_empty()) > <If cond=MaybeSignal::derive( move || is_header || !title.get().is_empty()) >
<Then slot> <Then slot>
<div class="melt-card__header"> <div class="melt-card__header">
<div class="melt-card__header-content"> <div class="melt-card__header-content">
@ -48,25 +47,25 @@ pub fn Card(
<Fallback slot> <Fallback slot>
{ title.get() } { title.get() }
</Fallback> </Fallback>
{ (header.children)(cx) } { (header.children)() }
</OptionComp> </OptionComp>
</div> </div>
<OptionComp value=header_extra.clone() bind:header_extra> <OptionComp value=header_extra.clone() bind:header_extra>
<div class="melt-card__header-extra"> <div class="melt-card__header-extra">
{ (header_extra.children)(cx) } { (header_extra.children)() }
</div> </div>
</OptionComp> </OptionComp>
</div> </div>
</Then> </Then>
</If> </If>
<div class="melt-card__content"> <div class="melt-card__content">
{ children(cx) } { children() }
</div> </div>
<OptionComp value=card_footer bind:footer> <OptionComp value=card_footer bind:footer>
<If cond=footer.if_ > <If cond=footer.if_ >
<Then slot> <Then slot>
<div class="melt-card__footer"> <div class="melt-card__footer">
{ (footer.children)(cx) } { (footer.children)() }
</div> </div>
</Then> </Then>
</If> </If>

View file

@ -4,17 +4,13 @@ use leptos::*;
use stylers::style_sheet_str; use stylers::style_sheet_str;
#[component] #[component]
pub fn Checkbox( pub fn Checkbox(#[prop(into)] checked: RwSignal<bool>, children: Children) -> impl IntoView {
cx: Scope, let theme = use_theme(Theme::light);
#[prop(into)] checked: RwSignal<bool>,
children: Children,
) -> impl IntoView {
let theme = use_theme(cx, Theme::light);
let class_name = mount_style("checkbox", || { let class_name = mount_style("checkbox", || {
style_sheet_str!("./src/checkbox/checkbox.css") style_sheet_str!("./src/checkbox/checkbox.css")
}); });
let css_vars = create_memo(cx, move |_| { let css_vars = create_memo(move |_| {
let mut css_vars = String::new(); let mut css_vars = String::new();
let theme = theme.get(); let theme = theme.get();
let bg_color = theme.common.color_primary; let bg_color = theme.common.color_primary;
@ -22,7 +18,7 @@ pub fn Checkbox(
css_vars css_vars
}); });
view! {cx, class=class_name, view! { class=class_name,
<div class:melt-checkbox=true class=("melt-checkbox--checked", move || checked.get()) style=move || css_vars.get() <div class:melt-checkbox=true class=("melt-checkbox--checked", move || checked.get()) style=move || css_vars.get()
on:click=move |_| checked.set(!checked.get_untracked())> on:click=move |_| checked.set(!checked.get_untracked())>
<input class="melt-checkbox__input" type="checkbox" /> <input class="melt-checkbox__input" type="checkbox" />
@ -34,7 +30,7 @@ pub fn Checkbox(
</If> </If>
</div> </div>
<div class="melt-checkbox__label"> <div class="melt-checkbox__label">
{ children(cx) } { children() }
</div> </div>
</div> </div>
} }

View file

@ -1,10 +1,10 @@
use leptos::*; use leptos::*;
#[component] #[component]
pub fn Code(cx: Scope, children: Children) -> impl IntoView { pub fn Code(children: Children) -> impl IntoView {
view! { cx, view! {
<code class="melt-code"> <code class="melt-code">
{ children(cx) } { children() }
</code> </code>
} }
} }

View file

@ -1,5 +1,5 @@
use leptos::*;
use super::Fallback; use super::Fallback;
use leptos::*;
#[slot] #[slot]
pub struct Then { pub struct Then {
@ -14,7 +14,6 @@ pub struct ElseIf {
#[component] #[component]
pub fn If( pub fn If(
cx: Scope,
#[prop(into)] cond: MaybeSignal<bool>, #[prop(into)] cond: MaybeSignal<bool>,
then: Then, then: Then,
#[prop(default=vec![])] else_if: Vec<ElseIf>, #[prop(default=vec![])] else_if: Vec<ElseIf>,
@ -22,13 +21,13 @@ pub fn If(
) -> impl IntoView { ) -> impl IntoView {
move || { move || {
if cond.get() { if cond.get() {
(then.children)(cx).into_view(cx) (then.children)().into_view()
} else if let Some(else_if) = else_if.iter().find(|i| i.cond.get()) { } else if let Some(else_if) = else_if.iter().find(|i| i.cond.get()) {
(else_if.children)(cx).into_view(cx) (else_if.children)().into_view()
} else if let Some(fallback) = &fallback { } else if let Some(fallback) = &fallback {
(fallback.children)(cx).into_view(cx) (fallback.children)().into_view()
} else { } else {
().into_view(cx) ().into_view()
} }
} }
} }

View file

@ -2,8 +2,8 @@ mod if_comp;
mod option_comp; mod option_comp;
pub use if_comp::*; pub use if_comp::*;
pub use option_comp::*;
use leptos::*; use leptos::*;
pub use option_comp::*;
#[slot] #[slot]
pub struct Fallback { pub struct Fallback {

View file

@ -1,22 +1,21 @@
use leptos::*;
use super::Fallback; use super::Fallback;
use leptos::*;
#[component] #[component]
pub fn OptionComp<T, CF, IV>( pub fn OptionComp<T, CF, IV>(
cx: Scope,
value: Option<T>, value: Option<T>,
children: CF, children: CF,
#[prop(optional)] fallback: Option<Fallback>, #[prop(optional)] fallback: Option<Fallback>,
) -> impl IntoView ) -> impl IntoView
where where
CF: Fn(Scope, T) -> IV + 'static, CF: Fn(T) -> IV + 'static,
IV: IntoView, IV: IntoView,
{ {
if let Some(value) = value { if let Some(value) = value {
children(cx, value).into_view(cx) children(value).into_view()
} else if let Some(fallback) = fallback { } else if let Some(fallback) = fallback {
(fallback.children)(cx).into_view(cx) (fallback.children)().into_view()
} else { } else {
().into_view(cx) ().into_view()
} }
} }

View file

@ -1,31 +1,30 @@
// copy https://github.com/Carlosted/leptos-icons // copy https://github.com/Carlosted/leptos-icons
// leptos updated version causes leptos_icons error // leptos updated version causes leptos_icons error
pub use icondata::*; pub use icondata::*;
use leptos::SignalGet; use leptos::*;
/// The Icon component. /// The Icon component.
#[leptos::component] #[component]
pub fn Icon( pub fn Icon(
cx: leptos::Scope,
/// The icon to show. /// The icon to show.
#[prop(into)] #[prop(into)]
icon: leptos::MaybeSignal<Icon>, icon: MaybeSignal<Icon>,
/// The width of the icon (horizontal side length of the square surrounding the icon). Defaults to "1em". /// The width of the icon (horizontal side length of the square surrounding the icon). Defaults to "1em".
#[prop(into, optional)] #[prop(into, optional)]
width: Option<leptos::MaybeSignal<String>>, width: Option<MaybeSignal<String>>,
/// The height of the icon (vertical side length of the square surrounding the icon). Defaults to "1em". /// The height of the icon (vertical side length of the square surrounding the icon). Defaults to "1em".
#[prop(into, optional)] #[prop(into, optional)]
height: Option<leptos::MaybeSignal<String>>, height: Option<MaybeSignal<String>>,
/// HTML class attribute. /// HTML class attribute.
#[prop(into, optional)] #[prop(into, optional)]
class: Option<leptos::MaybeSignal<String>>, class: Option<MaybeSignal<String>>,
/// HTML style attribute. /// HTML style attribute.
#[prop(into, optional)] #[prop(into, optional)]
style: Option<leptos::MaybeSignal<String>>, style: Option<MaybeSignal<String>>,
) -> impl leptos::IntoView { ) -> impl IntoView {
let icon: IconData = icon.get().into(); let icon: IconData = icon.get().into();
let mut svg = leptos::svg::svg(cx); let mut svg = svg::svg();
if let Some(classes) = class { if let Some(classes) = class {
svg = svg.classes(classes.get()); svg = svg.classes(classes.get());
} }
@ -45,20 +44,20 @@ pub fn Icon(
// We ignore the width and height attributes of the icon, even if the user hasn't specified any. // We ignore the width and height attributes of the icon, even if the user hasn't specified any.
svg = svg.attr( svg = svg.attr(
"width", "width",
leptos::Attribute::String(match (width, icon.width) { Attribute::String(match (width, icon.width) {
(Some(a), Some(_b)) => std::borrow::Cow::from(a.get()), (Some(a), Some(_b)) => Oco::from(a.get()),
(Some(a), None) => std::borrow::Cow::from(a.get()), (Some(a), None) => Oco::from(a.get()),
(None, Some(_b)) => std::borrow::Cow::from("1em"), (None, Some(_b)) => Oco::from("1em"),
(None, None) => std::borrow::Cow::from("1em"), (None, None) => Oco::from("1em"),
}), }),
); );
svg = svg.attr( svg = svg.attr(
"height", "height",
leptos::Attribute::String(match (height, icon.height) { Attribute::String(match (height, icon.height) {
(Some(a), Some(_b)) => std::borrow::Cow::from(a.get()), (Some(a), Some(_b)) => Oco::from(a.get()),
(Some(a), None) => std::borrow::Cow::from(a.get()), (Some(a), None) => Oco::from(a.get()),
(None, Some(_b)) => std::borrow::Cow::from("1em"), (None, Some(_b)) => Oco::from("1em"),
(None, None) => std::borrow::Cow::from("1em"), (None, None) => Oco::from("1em"),
}), }),
); );
if let Some(view_box) = icon.view_box { if let Some(view_box) = icon.view_box {
@ -79,5 +78,5 @@ pub fn Icon(
svg = svg.attr("fill", icon.fill.unwrap_or("currentColor")); svg = svg.attr("fill", icon.fill.unwrap_or("currentColor"));
svg = svg.attr("role", "graphics-symbol"); svg = svg.attr("role", "graphics-symbol");
svg = svg.inner_html(icon.data); svg = svg.inner_html(icon.data);
leptos::IntoView::into_view(svg, cx) IntoView::into_view(svg)
} }

View file

@ -1,9 +1,7 @@
use leptos::*; use leptos::*;
#[component] #[component]
pub fn Image( pub fn Image(
cx: Scope,
#[prop(optional, into)] src: MaybeSignal<String>, #[prop(optional, into)] src: MaybeSignal<String>,
#[prop(optional, into)] alt: MaybeSignal<String>, #[prop(optional, into)] alt: MaybeSignal<String>,
#[prop(optional, into)] width: MaybeSignal<String>, #[prop(optional, into)] width: MaybeSignal<String>,
@ -11,7 +9,6 @@ pub fn Image(
#[prop(optional, into)] border_radius: MaybeSignal<String>, #[prop(optional, into)] border_radius: MaybeSignal<String>,
#[prop(optional, into)] object_fit: MaybeSignal<String>, #[prop(optional, into)] object_fit: MaybeSignal<String>,
) -> impl IntoView { ) -> impl IntoView {
let style = move || { let style = move || {
let mut style = String::new(); let mut style = String::new();
@ -33,7 +30,7 @@ pub fn Image(
style style
}; };
view! { view! {
cx,
<img src=move || src.get() alt=move || alt.get() style=style object_fit=move || object_fit.get()/> <img src=move || src.get() alt=move || alt.get() style=style object_fit=move || object_fit.get()/>
} }
} }

View file

@ -25,21 +25,20 @@ impl InputType {
#[component] #[component]
pub fn Input( pub fn Input(
cx: Scope,
#[prop(into)] value: RwSignal<String>, #[prop(into)] value: RwSignal<String>,
#[prop(optional, into)] type_: MaybeSignal<InputType>, #[prop(optional, into)] type_: MaybeSignal<InputType>,
) -> impl IntoView { ) -> impl IntoView {
let theme = use_theme(cx, Theme::light); let theme = use_theme(Theme::light);
let class_name = mount_style("input", || style_sheet_str!("./src/input/input.css")); let class_name = mount_style("input", || style_sheet_str!("./src/input/input.css"));
let input_ref = create_node_ref::<html::Input>(cx); let input_ref = create_node_ref::<html::Input>();
input_ref.on_load(cx, move |input| { input_ref.on_load(move |input| {
input.on(ev::input, move |ev| { input.on(ev::input, move |ev| {
value.set(event_target_value(&ev)); value.set(event_target_value(&ev));
}); });
}); });
let css_vars = create_memo(cx, move |_| { let css_vars = create_memo(move |_| {
let mut css_vars = String::new(); let mut css_vars = String::new();
let theme = theme.get(); let theme = theme.get();
let border_color_hover = theme.common.color_primary.clone(); let border_color_hover = theme.common.color_primary.clone();
@ -49,7 +48,7 @@ pub fn Input(
css_vars css_vars
}); });
view! { view! {
cx, class=class_name, class=class_name,
<div class:melt-input=true style=move || css_vars.get()> <div class:melt-input=true style=move || css_vars.get()>
<input type=move || type_.get().as_str() prop:value=move || value.get() ref=input_ref class="melt-input__input-el"/> <input type=move || type_.get().as_str() prop:value=move || value.get() ref=input_ref class="melt-input__input-el"/>
</div> </div>

View file

@ -1,9 +1,7 @@
use crate::theme::ThemeMethod; use crate::theme::ThemeMethod;
#[derive(Clone)] #[derive(Clone)]
pub struct InputTheme { pub struct InputTheme {}
}
impl ThemeMethod for InputTheme { impl ThemeMethod for InputTheme {
fn light() -> Self { fn light() -> Self {

View file

@ -2,13 +2,12 @@ use leptos::*;
#[component] #[component]
pub fn LayoutHeader( pub fn LayoutHeader(
cx: Scope,
#[prop(optional, into)] style: MaybeSignal<String>, #[prop(optional, into)] style: MaybeSignal<String>,
children: Children, children: Children,
) -> impl IntoView { ) -> impl IntoView {
view! { cx, view! {
<div class="melt-layout-header" style=move || style.get()> <div class="melt-layout-header" style=move || style.get()>
{ children(cx) } { children() }
</div> </div>
} }
} }

View file

@ -3,13 +3,13 @@ use leptos::*;
use stylers::style_sheet_str; use stylers::style_sheet_str;
#[component] #[component]
pub fn LayoutSider(cx: Scope, children: Children) -> impl IntoView { pub fn LayoutSider(children: Children) -> impl IntoView {
let class_name = mount_style("layout-sider", || { let class_name = mount_style("layout-sider", || {
style_sheet_str!("./src/layout/layout-sider.css") style_sheet_str!("./src/layout/layout-sider.css")
}); });
view! { cx, class=class_name, view! { class=class_name,
<div class="melt-layout-sider"> <div class="melt-layout-sider">
{ children(cx) } { children() }
</div> </div>
} }
} }

View file

@ -25,7 +25,6 @@ impl LayoutPosition {
#[component] #[component]
pub fn Layout( pub fn Layout(
cx: Scope,
#[prop(optional, into)] style: MaybeSignal<String>, #[prop(optional, into)] style: MaybeSignal<String>,
#[prop(optional)] position: LayoutPosition, #[prop(optional)] position: LayoutPosition,
#[prop(optional, into)] has_sider: MaybeSignal<bool>, #[prop(optional, into)] has_sider: MaybeSignal<bool>,
@ -33,16 +32,16 @@ pub fn Layout(
) -> impl IntoView { ) -> impl IntoView {
let class_name = mount_style("layout", || style_sheet_str!("./src/layout/layout.css")); let class_name = mount_style("layout", || style_sheet_str!("./src/layout/layout.css"));
let style = create_memo(cx, move |_| { let style = create_memo(move |_| {
let mut style = style.get(); let mut style = style.get();
if has_sider.get() { if has_sider.get() {
style.push_str("display: flex; flex-wrap: nowrap; flex-direction: row; width: 100;%") style.push_str("display: flex; flex-wrap: nowrap; flex-direction: row; width: 100;%")
} }
style style
}); });
view! { cx, class=class_name, view! { class=class_name,
<div class="melt-layout" class=("melt-layout--absolute-positioned", position == LayoutPosition::ABSOLUTE) style=move || style.get()> <div class="melt-layout" class=("melt-layout--absolute-positioned", position == LayoutPosition::ABSOLUTE) style=move || style.get()>
{ children(cx) } { children() }
</div> </div>
} }
} }

View file

@ -5,18 +5,17 @@ use stylers::style_sheet_str;
#[component] #[component]
pub fn MenuItem( pub fn MenuItem(
cx: Scope,
#[prop(into)] key: MaybeSignal<&'static str>, #[prop(into)] key: MaybeSignal<&'static str>,
#[prop(into)] label: MaybeSignal<String>, #[prop(into)] label: MaybeSignal<String>,
) -> impl IntoView { ) -> impl IntoView {
let class_name = mount_style("menu-item", || style_sheet_str!("./src/menu/menu-item.css")); let class_name = mount_style("menu-item", || style_sheet_str!("./src/menu/menu-item.css"));
let theme = use_theme(cx, Theme::light); let theme = use_theme(Theme::light);
let menu = use_menu(cx); let menu = use_menu();
let onclick_select = move |_| { let onclick_select = move |_| {
menu.set(MenuInjectionKey::new(key.get().to_string())); menu.set(MenuInjectionKey::new(key.get().to_string()));
}; };
let css_vars = create_memo(cx, move |_| { let css_vars = create_memo(move |_| {
let mut css_vars = String::new(); let mut css_vars = String::new();
let theme = theme.get(); let theme = theme.get();
let font_color = theme.common.color_primary.clone(); let font_color = theme.common.color_primary.clone();
@ -26,7 +25,7 @@ pub fn MenuItem(
css_vars.push_str(&format!("--border-radius: {border_radius};")); css_vars.push_str(&format!("--border-radius: {border_radius};"));
css_vars css_vars
}); });
view! {cx, class=class_name, view! { class=class_name,
<div class="melt-menu-item"> <div class="melt-menu-item">
<div class="melt-menu-item__content" class=("melt-menu-item__content--selected", move || menu.get().value == key.get()) on:click=onclick_select style=move || css_vars.get()> <div class="melt-menu-item__content" class=("melt-menu-item__content--selected", move || menu.get().value == key.get()) on:click=onclick_select style=move || css_vars.get()>
{ move || label.get() } { move || label.get() }

View file

@ -4,13 +4,9 @@ use leptos::*;
pub use menu_item::*; pub use menu_item::*;
#[component] #[component]
pub fn Menu( pub fn Menu(#[prop(into)] selected: RwSignal<String>, children: Children) -> impl IntoView {
cx: Scope, let menu_injection_key = create_rw_signal(MenuInjectionKey::new(selected.get_untracked()));
#[prop(into)] selected: RwSignal<String>, create_effect(move |_| {
children: Children,
) -> impl IntoView {
let menu_injection_key = create_rw_signal(cx, MenuInjectionKey::new(selected.get()));
create_effect(cx, move |_| {
let selected_key = selected.get(); let selected_key = selected.get();
let key = menu_injection_key.get_untracked(); let key = menu_injection_key.get_untracked();
if selected_key != key.value { if selected_key != key.value {
@ -18,17 +14,17 @@ pub fn Menu(
} }
}); });
create_effect(cx, move |_| { create_effect(move |_| {
let selected_key = selected.get_untracked(); let selected_key = selected.get_untracked();
let key = menu_injection_key.get(); let key = menu_injection_key.get();
if selected_key != key.value { if selected_key != key.value {
selected.set(key.value); selected.set(key.value);
} }
}); });
provide_context(cx, menu_injection_key); provide_context(menu_injection_key);
view! {cx, view! {
<div class="melt-menu"> <div class="melt-menu">
{ children(cx) } { children() }
</div> </div>
} }
} }
@ -38,13 +34,12 @@ pub struct MenuInjectionKey {
value: String, value: String,
} }
impl MenuInjectionKey { impl MenuInjectionKey {
pub fn new(value: String) -> Self { pub fn new(value: String) -> Self {
Self { value } Self { value }
} }
} }
pub fn use_menu(cx: Scope) -> RwSignal<MenuInjectionKey> { pub fn use_menu() -> RwSignal<MenuInjectionKey> {
use_context::<RwSignal<MenuInjectionKey>>(cx).expect("MenuInjectionKey not exist") use_context::<RwSignal<MenuInjectionKey>>().expect("MenuInjectionKey not exist")
} }

View file

@ -5,7 +5,6 @@ use web_sys::MouseEvent;
#[component] #[component]
pub fn NavBar( pub fn NavBar(
cx: Scope,
#[prop(optional, into)] title: MaybeSignal<&'static str>, #[prop(optional, into)] title: MaybeSignal<&'static str>,
#[prop(optional, into)] left_arrow: MaybeSignal<bool>, #[prop(optional, into)] left_arrow: MaybeSignal<bool>,
#[prop(optional, into)] left_text: MaybeSignal<&'static str>, #[prop(optional, into)] left_text: MaybeSignal<&'static str>,
@ -28,9 +27,9 @@ pub fn NavBar(
} }
}; };
view! { cx, class=class_name, view! { class=class_name,
<div class="melt-nav-bar"> <div class="melt-nav-bar">
<If cond=MaybeSignal::derive(cx, move || left_arrow.get() || !left_text.get().is_empty())> <If cond=MaybeSignal::derive( move || left_arrow.get() || !left_text.get().is_empty())>
<Then slot> <Then slot>
<div class="melt-nav-bar__left" on:click=onclick_left> <div class="melt-nav-bar__left" on:click=onclick_left>
<If cond=left_arrow> <If cond=left_arrow>
@ -45,7 +44,7 @@ pub fn NavBar(
<div class="melt-nav-bar__center"> <div class="melt-nav-bar__center">
{ move || title.get() } { move || title.get() }
</div> </div>
<If cond=MaybeSignal::derive(cx, move || !right_text.get().is_empty())> <If cond=MaybeSignal::derive( move || !right_text.get().is_empty())>
<Then slot> <Then slot>
<div class="melt-nav-bar__right" on:click=onclick_right> <div class="melt-nav-bar__right" on:click=onclick_right>
{ right_text.get() } { right_text.get() }

View file

@ -6,17 +6,13 @@ use stylers::style_sheet_str;
pub use tabbar_item::*; pub use tabbar_item::*;
#[component] #[component]
pub fn Tabbar( pub fn Tabbar(#[prop(into)] selected: RwSignal<String>, children: Children) -> impl IntoView {
cx: Scope,
#[prop(into)] selected: RwSignal<String>,
children: Children,
) -> impl IntoView {
let class_name = mount_style("tabbar", || { let class_name = mount_style("tabbar", || {
style_sheet_str!("./src/mobile/tabbar/tabbar.css") style_sheet_str!("./src/mobile/tabbar/tabbar.css")
}); });
let tabbar_injection_key = create_rw_signal(cx, TabbarInjectionKey::new(selected.get())); let tabbar_injection_key = create_rw_signal(TabbarInjectionKey::new(selected.get()));
create_effect(cx, move |_| { create_effect(move |_| {
let selected_key = selected.get(); let selected_key = selected.get();
let key = tabbar_injection_key.get_untracked(); let key = tabbar_injection_key.get_untracked();
if selected_key != key.value { if selected_key != key.value {
@ -24,17 +20,17 @@ pub fn Tabbar(
} }
}); });
create_effect(cx, move |_| { create_effect(move |_| {
let selected_key = selected.get_untracked(); let selected_key = selected.get_untracked();
let key = tabbar_injection_key.get(); let key = tabbar_injection_key.get();
if selected_key != key.value { if selected_key != key.value {
selected.set(key.value); selected.set(key.value);
} }
}); });
provide_context(cx, tabbar_injection_key); provide_context(tabbar_injection_key);
view! {cx, class=class_name, view! { class=class_name,
<div class="melt-tabbar"> <div class="melt-tabbar">
{ children(cx) } { children() }
</div> </div>
} }
} }
@ -50,6 +46,6 @@ impl TabbarInjectionKey {
} }
} }
pub fn use_tabbar(cx: Scope) -> RwSignal<TabbarInjectionKey> { pub fn use_tabbar() -> RwSignal<TabbarInjectionKey> {
use_context::<RwSignal<TabbarInjectionKey>>(cx).expect("TabbarInjectionKey not exist") use_context::<RwSignal<TabbarInjectionKey>>().expect("TabbarInjectionKey not exist")
} }

View file

@ -6,7 +6,6 @@ use stylers::style_sheet_str;
#[component] #[component]
pub fn TabbarItem( pub fn TabbarItem(
cx: Scope,
#[prop(into)] name: MaybeSignal<&'static str>, #[prop(into)] name: MaybeSignal<&'static str>,
#[prop(optional, into)] icon: Option<Icon>, #[prop(optional, into)] icon: Option<Icon>,
children: Children, children: Children,
@ -14,13 +13,13 @@ pub fn TabbarItem(
let class_name = mount_style("tabbar-item", || { let class_name = mount_style("tabbar-item", || {
style_sheet_str!("./src/mobile/tabbar/tabbar-item.css") style_sheet_str!("./src/mobile/tabbar/tabbar-item.css")
}); });
let theme = use_theme(cx, Theme::light); let theme = use_theme(Theme::light);
let tabbar = use_tabbar(cx); let tabbar = use_tabbar();
let onclick_select = move |_| { let onclick_select = move |_| {
tabbar.set(TabbarInjectionKey::new(name.get().to_string())); tabbar.set(TabbarInjectionKey::new(name.get().to_string()));
}; };
let css_vars = create_memo(cx, move |_| { let css_vars = create_memo(move |_| {
let mut css_vars = String::new(); let mut css_vars = String::new();
let theme = theme.get(); let theme = theme.get();
let font_color = theme.common.color_primary.clone(); let font_color = theme.common.color_primary.clone();
@ -28,13 +27,13 @@ pub fn TabbarItem(
css_vars css_vars
}); });
view! {cx, class=class_name, view! { class=class_name,
<div class="melt-tabbar-item" class=("melt-tabbar-item--selected", move || tabbar.get().value == name.get()) on:click=onclick_select style=move || css_vars.get()> <div class="melt-tabbar-item" class=("melt-tabbar-item--selected", move || tabbar.get().value == name.get()) on:click=onclick_select style=move || css_vars.get()>
<OptionComp value=icon bind:icon> <OptionComp value=icon bind:icon>
<Icon icon=icon width="22px" height="22px" class="melt-tabbar-item__icon"/> <Icon icon=icon width="22px" height="22px" class="melt-tabbar-item__icon"/>
</OptionComp> </OptionComp>
<div class="melt-tabbar-item__content"> <div class="melt-tabbar-item__content">
{ children(cx) } { children() }
</div> </div>
</div> </div>
} }

View file

@ -9,16 +9,16 @@ pub struct ToastOptions {
pub duration: Duration, pub duration: Duration,
} }
pub fn show_toast(cx: Scope, options: ToastOptions) { pub fn show_toast(options: ToastOptions) {
let class_name = mount_style("toast", || style_sheet_str!("./src/mobile/toast/toast.css")); let class_name = mount_style("toast", || style_sheet_str!("./src/mobile/toast/toast.css"));
let parent = Element::from(document().body().expect("body element not to exist")); let parent = Element::from(document().body().expect("body element not to exist"));
let children = view! {cx, class=class_name, let children = view! { class=class_name,
<div class="melt-toast"> <div class="melt-toast">
{ options.message } { options.message }
</div> </div>
}; };
let node = children.into_view(cx); let node = children.into_view();
#[cfg(all(target_arch = "wasm32"))] #[cfg(all(target_arch = "wasm32"))]
{ {
@ -32,4 +32,9 @@ pub fn show_toast(cx: Scope, options: ToastOptions) {
options.duration, options.duration,
); );
} }
#[cfg(not(target_arch = "wasm32"))]
{
_ = parent;
_ = node;
}
} }

View file

@ -13,7 +13,6 @@ pub struct ModalFooter {
#[component] #[component]
pub fn Modal( pub fn Modal(
cx: Scope,
#[prop(into)] show: RwSignal<bool>, #[prop(into)] show: RwSignal<bool>,
#[prop(optional, into)] title: MaybeSignal<&'static str>, #[prop(optional, into)] title: MaybeSignal<&'static str>,
children: Children, children: Children,
@ -22,7 +21,7 @@ pub fn Modal(
let class_name = mount_style("modal", || style_sheet_str!("./src/modal/modal.css")); let class_name = mount_style("modal", || style_sheet_str!("./src/modal/modal.css"));
view! { view! {
cx, class=class_name, class=class_name,
<Teleport> <Teleport>
<div class="melt-modal-container" style=move || if show.get() { "" } else { "display: none" }> <div class="melt-modal-container" style=move || if show.get() { "" } else { "display: none" }>
<div class="melt-modal-mask"></div> <div class="melt-modal-mask"></div>
@ -38,10 +37,10 @@ pub fn Modal(
<Icon icon=Icon::from(AiIcon::AiCloseOutlined)/> <Icon icon=Icon::from(AiIcon::AiCloseOutlined)/>
</span> </span>
</CardHeaderExtra> </CardHeaderExtra>
{ children(cx) } { children() }
<CardFooter slot if_=modal_footer.is_some()> <CardFooter slot if_=modal_footer.is_some()>
<OptionComp value=modal_footer.as_ref() bind:footer> <OptionComp value=modal_footer.as_ref() bind:footer>
{ (footer.children)(cx) } { (footer.children)() }
</OptionComp> </OptionComp>
</CardFooter> </CardFooter>
</Card> </Card>

View file

@ -1,21 +1,22 @@
use crate::{utils::mount_style::mount_style, components::*}; use crate::{components::*, utils::mount_style::mount_style};
use leptos::*; use leptos::*;
use stylers::style_sheet_str; use stylers::style_sheet_str;
#[component] #[component]
pub fn Progress( pub fn Progress(
cx: Scope,
#[prop(optional, into)] left_tip: MaybeSignal<&'static str>, #[prop(optional, into)] left_tip: MaybeSignal<&'static str>,
#[prop(optional, into)] right_tip: MaybeSignal<&'static str>, #[prop(optional, into)] right_tip: MaybeSignal<&'static str>,
percentage: ReadSignal<f64>, percentage: ReadSignal<f64>,
) -> impl IntoView { ) -> impl IntoView {
let class_name = mount_style("progress", || style_sheet_str!("./src/progress/progress.css")); let class_name = mount_style("progress", || {
style_sheet_str!("./src/progress/progress.css")
});
let style = move || format!("width: {}%", percentage.get()); let style = move || format!("width: {}%", percentage.get());
view! { view! {
cx, class=class_name, class=class_name,
<div class="melt-progress"> <div class="melt-progress">
<span class="melt-progress__tip-left"> <span class="melt-progress__tip-left">
<If cond=MaybeSignal::derive(cx, move || !left_tip.get().is_empty())> <If cond=MaybeSignal::derive( move || !left_tip.get().is_empty())>
<Then slot> <Then slot>
{ left_tip.get() } { left_tip.get() }
</Then> </Then>
@ -27,7 +28,7 @@ pub fn Progress(
</span> </span>
</span> </span>
<span class="melt-progress__tip-right"> <span class="melt-progress__tip-right">
<If cond=MaybeSignal::derive(cx, move || !right_tip.get().is_empty())> <If cond=MaybeSignal::derive( move || !right_tip.get().is_empty())>
<Then slot> <Then slot>
{ right_tip.get() } { right_tip.get() }
</Then> </Then>

View file

@ -1,9 +1,4 @@
use crate::{ use crate::{teleport::Teleport, theme::use_theme, utils::mount_style::mount_style, Theme};
teleport::Teleport,
theme::use_theme,
utils::{dom::window_event_listener, mount_style::mount_style},
Theme,
};
use leptos::*; use leptos::*;
use std::hash::Hash; use std::hash::Hash;
use stylers::style_sheet_str; use stylers::style_sheet_str;
@ -17,7 +12,6 @@ pub struct SelectOption<T> {
#[component] #[component]
pub fn Select<T>( pub fn Select<T>(
cx: Scope,
#[prop(into)] value: RwSignal<Option<T>>, #[prop(into)] value: RwSignal<Option<T>>,
#[prop(optional, into)] options: MaybeSignal<Vec<SelectOption<T>>>, #[prop(optional, into)] options: MaybeSignal<Vec<SelectOption<T>>>,
) -> impl IntoView ) -> impl IntoView
@ -26,8 +20,8 @@ where
{ {
let class_name = mount_style("select", || style_sheet_str!("./src/select/select.css")); let class_name = mount_style("select", || style_sheet_str!("./src/select/select.css"));
let theme = use_theme(cx, Theme::light); let theme = use_theme(Theme::light);
let css_vars = create_memo(cx, move |_| { let css_vars = create_memo(move |_| {
let mut css_vars = String::new(); let mut css_vars = String::new();
let theme = theme.get(); let theme = theme.get();
let bg_color = theme.common.color_primary; let bg_color = theme.common.color_primary;
@ -37,9 +31,9 @@ where
css_vars css_vars
}); });
let is_show_popover = create_rw_signal(cx, false); let is_show_popover = create_rw_signal(false);
let trigger_ref = create_node_ref::<html::Div>(cx); let trigger_ref = create_node_ref::<html::Div>();
let popover_ref = create_node_ref::<html::Div>(cx); let popover_ref = create_node_ref::<html::Div>();
let show_popover = move |_| { let show_popover = move |_| {
let rect = trigger_ref.get().unwrap().get_bounding_client_rect(); let rect = trigger_ref.get().unwrap().get_bounding_client_rect();
is_show_popover.set(true); is_show_popover.set(true);
@ -74,10 +68,10 @@ where
} }
is_show_popover.set(false); is_show_popover.set(false);
}); });
on_cleanup(cx, timer); on_cleanup(move || timer.remove());
let temp_options = options.clone(); let temp_options = options.clone();
let select_option_label = create_memo(cx, move |_| match value.get() { let select_option_label = create_memo(move |_| match value.get() {
Some(value) => temp_options Some(value) => temp_options
.get() .get()
.iter() .iter()
@ -85,7 +79,7 @@ where
.map_or(String::new(), |v| v.label.clone()), .map_or(String::new(), |v| v.label.clone()),
None => String::new(), None => String::new(),
}); });
view! { cx, class=class_name, view! { class=class_name,
<div class="melt-select" ref=trigger_ref on:click=show_popover style=move || css_vars.get()> <div class="melt-select" ref=trigger_ref on:click=show_popover style=move || css_vars.get()>
{ {
move || select_option_label.get() move || select_option_label.get()
@ -96,14 +90,14 @@ where
<For <For
each=move || options.get() each=move || options.get()
key=move |item| item.value.clone() key=move |item| item.value.clone()
view=move |cx, item| { view=move | item| {
let item = store_value(cx, item); let item = store_value( item);
let onclick = move |_| { let onclick = move |_| {
let SelectOption { value: item_value, label: _ } = item.get_value(); let SelectOption { value: item_value, label: _ } = item.get_value();
value.set(Some(item_value)); value.set(Some(item_value));
is_show_popover.set(false); is_show_popover.set(false);
}; };
view! { cx, class=class_name, view! { class=class_name,
<div class="melt-select-menu__item" class=("melt-select-menu__item-selected", move || value.get() == Some(item.get_value().value) ) on:click=onclick> <div class="melt-select-menu__item" class=("melt-select-menu__item-selected", move || value.get() == Some(item.get_value().value) ) on:click=onclick>
{ item.get_value().label } { item.get_value().label }
</div> </div>

View file

@ -1,20 +1,15 @@
use crate::{ use crate::{theme::use_theme, utils::mount_style::mount_style, Theme};
theme::use_theme,
utils::{dom::window_event_listener, mount_style::mount_style},
Theme,
};
use leptos::*; use leptos::*;
use stylers::style_sheet_str; use stylers::style_sheet_str;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
#[component] #[component]
pub fn Slider( pub fn Slider(
cx: Scope,
#[prop(into)] value: RwSignal<f64>, #[prop(into)] value: RwSignal<f64>,
#[prop(default = MaybeSignal::Static(100f64), into)] max: MaybeSignal<f64>, #[prop(default = MaybeSignal::Static(100f64), into)] max: MaybeSignal<f64>,
) -> impl IntoView { ) -> impl IntoView {
let theme = use_theme(cx, Theme::light); let theme = use_theme(Theme::light);
let css_vars = create_memo(cx, move |_| { let css_vars = create_memo(move |_| {
let mut css_vars = String::new(); let mut css_vars = String::new();
let theme = theme.get(); let theme = theme.get();
let bg_color = theme.common.color_primary; let bg_color = theme.common.color_primary;
@ -23,7 +18,7 @@ pub fn Slider(
css_vars css_vars
}); });
let percentage = create_memo(cx, move |_| { let percentage = create_memo(move |_| {
if value.get() < 0.0 || max.get() <= 0.0 { if value.get() < 0.0 || max.get() <= 0.0 {
0f64 0f64
} else if value.get() >= max.get() { } else if value.get() >= max.get() {
@ -38,9 +33,9 @@ pub fn Slider(
value.set(val); value.set(val);
}; };
let rail_ref = create_node_ref::<html::Div>(cx); let rail_ref = create_node_ref::<html::Div>();
let (mouse_move_value, set_mouse_move_value) = create_signal::<Option<f64>>(cx, None); let (mouse_move_value, set_mouse_move_value) = create_signal::<Option<f64>>(None);
let (is_mouse_move, set_mouse_move) = create_signal(cx, false); let (is_mouse_move, set_mouse_move) = create_signal(false);
let on_mouse_down = move |_| { let on_mouse_down = move |_| {
set_mouse_move.set(true); set_mouse_move.set(true);
}; };
@ -48,7 +43,7 @@ pub fn Slider(
let on_mouse_up = window_event_listener(ev::mouseup, move |_| { let on_mouse_up = window_event_listener(ev::mouseup, move |_| {
set_mouse_move.set(false); set_mouse_move.set(false);
}); });
on_cleanup(cx, on_mouse_up); on_cleanup(move || on_mouse_up.remove());
let on_mouse_move = window_event_listener(ev::mousemove, move |ev| { let on_mouse_move = window_event_listener(ev::mousemove, move |ev| {
if is_mouse_move.get_untracked() { if is_mouse_move.get_untracked() {
@ -69,9 +64,9 @@ pub fn Slider(
}; };
} }
}); });
on_cleanup(cx, on_mouse_move); on_cleanup(move || on_mouse_move.remove());
view! {cx, class=class_name, view! { class=class_name,
<div class="melt-slider" style=move || css_vars.get()> <div class="melt-slider" style=move || css_vars.get()>
<div class="melt-slider-rail" ref=rail_ref> <div class="melt-slider-rail" ref=rail_ref>
<div class="melt-slider-rail__fill" style=move || format!("width: {}%", percentage.get())></div> <div class="melt-slider-rail__fill" style=move || format!("width: {}%", percentage.get())></div>

View file

@ -13,7 +13,7 @@ pub enum SpaceGap {
} }
#[component] #[component]
pub fn Space(cx: Scope, #[prop(optional)] gap: SpaceGap, children: Children) -> impl IntoView { pub fn Space(#[prop(optional)] gap: SpaceGap, children: Children) -> impl IntoView {
let class_name = mount_style("space", || style_sheet_str!("./src/space/space.css")); let class_name = mount_style("space", || style_sheet_str!("./src/space/space.css"));
let gap = match gap { let gap = match gap {
SpaceGap::SMALL => "gap: 4px 8px".into(), SpaceGap::SMALL => "gap: 4px 8px".into(),
@ -24,12 +24,12 @@ pub fn Space(cx: Scope, #[prop(optional)] gap: SpaceGap, children: Children) ->
}; };
view! { view! {
cx, class=class_name, class=class_name,
<div class="melt-space" style=format!("{gap};")> <div class="melt-space" style=format!("{gap};")>
{ {
children(cx).nodes.into_iter().map(|node| { children().nodes.into_iter().map(|node| {
view! { view! {
cx, class=class_name, class=class_name,
<div class="melt-space__item"> <div class="melt-space__item">
{node} {node}
</div> </div>

View file

@ -3,11 +3,11 @@ use leptos::*;
use stylers::style_sheet_str; use stylers::style_sheet_str;
#[component] #[component]
pub fn Table(cx: Scope, children: Children) -> impl IntoView { pub fn Table(children: Children) -> impl IntoView {
let class_name = mount_style("table", || style_sheet_str!("./src/table/table.css")); let class_name = mount_style("table", || style_sheet_str!("./src/table/table.css"));
view! {cx, class=class_name, view! { class=class_name,
<table class="melt-table"> <table class="melt-table">
{children(cx)} {children()}
</table> </table>
} }
} }

View file

@ -5,18 +5,15 @@ use stylers::style_sheet_str;
pub use tab::*; pub use tab::*;
#[component] #[component]
pub fn Tabs(cx: Scope, active_key: RwSignal<&'static str>, children: Children) -> impl IntoView { pub fn Tabs(active_key: RwSignal<&'static str>, children: Children) -> impl IntoView {
let class_name = mount_style("tabs", || style_sheet_str!("./src/tabs/tabs.css")); let class_name = mount_style("tabs", || style_sheet_str!("./src/tabs/tabs.css"));
let tab_options_vec = create_rw_signal(cx, vec![]); let tab_options_vec = create_rw_signal(vec![]);
provide_context( provide_context(TabsInjectionKey {
cx,
TabsInjectionKey {
active_key: active_key.clone(), active_key: active_key.clone(),
tab_options_vec: tab_options_vec.clone(), tab_options_vec: tab_options_vec.clone(),
}, });
); let theme = use_theme(Theme::light);
let theme = use_theme(cx, Theme::light); let css_vars = create_memo(move |_| {
let css_vars = create_memo(cx, move |_| {
let mut css_vars = String::new(); let mut css_vars = String::new();
let theme = theme.get(); let theme = theme.get();
let color_primary = theme.common.color_primary.clone(); let color_primary = theme.common.color_primary.clone();
@ -26,22 +23,22 @@ pub fn Tabs(cx: Scope, active_key: RwSignal<&'static str>, children: Children) -
css_vars css_vars
}); });
let label_line = create_rw_signal::<Option<TabsLabelLine>>(cx, None); let label_line = create_rw_signal::<Option<TabsLabelLine>>(None);
let label_line_style = create_memo(cx, move |_| { let label_line_style = create_memo(move |_| {
let mut style = String::new(); let mut style = String::new();
if let Some(line) = label_line.get() { if let Some(line) = label_line.get() {
style.push_str(&format!("width: {}px; left: {}px", line.width, line.left)) style.push_str(&format!("width: {}px; left: {}px", line.width, line.left))
} }
style style
}); });
let label_list_ref = create_node_ref::<html::Div>(cx); let label_list_ref = create_node_ref::<html::Div>();
view! { cx, class=class_name, view! { class=class_name,
<div class="melt-tabs" style=move || css_vars.get()> <div class="melt-tabs" style=move || css_vars.get()>
<div class="melt-tabs__label-list" ref=label_list_ref> <div class="melt-tabs__label-list" ref=label_list_ref>
<For each=move || tab_options_vec.get() key=move |v| v.key.clone() view=move |cx, options| { <For each=move || tab_options_vec.get() key=move |v| v.key.clone() view=move | options| {
let label_ref = create_node_ref::<html::Span>(cx); let label_ref = create_node_ref::<html::Span>();
create_effect(cx, move |_| { create_effect( move |_| {
let Some(label) = label_ref.get() else { let Some(label) = label_ref.get() else {
return; return;
}; };
@ -59,7 +56,7 @@ pub fn Tabs(cx: Scope, active_key: RwSignal<&'static str>, children: Children) -
}); });
} }
}); });
view! {cx, class=class_name, view! { class=class_name,
<span class="melt-tabs__label" class=("melt-tabs__label--active", move || options.key == active_key.get()) <span class="melt-tabs__label" class=("melt-tabs__label--active", move || options.key == active_key.get())
on:click=move |_| active_key.set(options.key) on:click=move |_| active_key.set(options.key)
ref=label_ref ref=label_ref
@ -72,7 +69,7 @@ pub fn Tabs(cx: Scope, active_key: RwSignal<&'static str>, children: Children) -
<span class="melt-tabs-label__line" style=move || label_line_style.get()></span> <span class="melt-tabs-label__line" style=move || label_line_style.get()></span>
</div> </div>
<div> <div>
{ children(cx) } { children() }
</div> </div>
</div> </div>
} }
@ -102,6 +99,6 @@ impl TabsInjectionKey {
} }
} }
pub fn use_tabs(cx: Scope) -> TabsInjectionKey { pub fn use_tabs() -> TabsInjectionKey {
use_context::<TabsInjectionKey>(cx).expect("TabsInjectionKey not exist") use_context::<TabsInjectionKey>().expect("TabsInjectionKey not exist")
} }

View file

@ -10,13 +10,13 @@ pub(crate) struct TabOptions {
} }
#[component] #[component]
pub fn Tab(cx: Scope, key: &'static str, label: &'static str, children: Children) -> impl IntoView { pub fn Tab(key: &'static str, label: &'static str, children: Children) -> impl IntoView {
let class_name = mount_style("tab", || style_sheet_str!("./src/tabs/tab.css")); let class_name = mount_style("tab", || style_sheet_str!("./src/tabs/tab.css"));
let tabs = use_tabs(cx); let tabs = use_tabs();
tabs.push_tab_options(TabOptions { key, label }); tabs.push_tab_options(TabOptions { key, label });
view! { cx, class=class_name, view! { class=class_name,
<div class="melt-tab" class=("melt-tab--hidden", move || key != tabs.get_key()) > <div class="melt-tab" class=("melt-tab--hidden", move || key != tabs.get_key()) >
{ children(cx) } { children() }
</div> </div>
} }
} }

View file

@ -3,11 +3,7 @@ use web_sys::Element;
/// https://github.com/solidjs/solid/blob/main/packages/solid/web/src/index.ts#L56 /// https://github.com/solidjs/solid/blob/main/packages/solid/web/src/index.ts#L56
#[component] #[component]
pub fn Teleport( pub fn Teleport(#[prop(optional)] to: Option<&'static str>, children: Children) -> impl IntoView {
cx: Scope,
#[prop(optional)] to: Option<&'static str>,
children: Children,
) -> impl IntoView {
let parent = if let Some(to) = to { let parent = if let Some(to) = to {
document() document()
.query_selector(to) .query_selector(to)
@ -20,16 +16,15 @@ pub fn Teleport(
#[cfg(all(target_arch = "wasm32"))] #[cfg(all(target_arch = "wasm32"))]
{ {
use leptos_dom::Mountable; use leptos_dom::Mountable;
let node = children(cx).into_view(cx); let node = children().into_view();
parent.append_child(&node.get_mountable_node()).unwrap(); parent.append_child(&node.get_mountable_node()).unwrap();
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
{ {
_ = cx;
_ = parent; _ = parent;
_ = children; _ = children;
} }
view! { cx, <></> } view! { <></> }
} }

View file

@ -31,24 +31,20 @@ impl CommonTheme {
fn common() -> Self { fn common() -> Self {
Self { Self {
font_family: "-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji'".into(), font_family: "-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji'".into(),
color_primary: "".into(), color_primary: "".into(),
color_success: "".into(), color_success: "".into(),
color_warning: "".into(), color_warning: "".into(),
color_error: "".into(), color_error: "".into(),
font_size: "14px".into(), font_size: "14px".into(),
font_size_small: "12px".into(), font_size_small: "12px".into(),
font_size_medium: "16px".into(), font_size_medium: "16px".into(),
font_size_large: "20px".into(), font_size_large: "20px".into(),
font_size_huge: "24px".into(), font_size_huge: "24px".into(),
line_height: "22px".into(), line_height: "22px".into(),
line_height_small: "20px".into(), line_height_small: "20px".into(),
line_height_medium: "24px".into(), line_height_medium: "24px".into(),
line_height_large: "28px".into(), line_height_large: "28px".into(),
line_height_huge: "32px".into(), line_height_huge: "32px".into(),
border_radius: "3px".into(), border_radius: "3px".into(),
border_radius_small: "2px".into(), border_radius_small: "2px".into(),
border_radius_medium: "4px".into(), border_radius_medium: "4px".into(),

View file

@ -50,16 +50,15 @@ impl ThemeMethod for Theme {
} }
} }
pub fn use_theme(cx: Scope, default: impl Fn() -> Theme) -> ReadSignal<Theme> { pub fn use_theme(default: impl Fn() -> Theme) -> ReadSignal<Theme> {
use_context::<ReadSignal<Theme>>(cx).unwrap_or_else(|| create_signal(cx, default()).0) use_context::<ReadSignal<Theme>>().unwrap_or_else(|| create_signal(default()).0)
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{use_theme, Theme}; use super::{use_theme, Theme};
use leptos::*;
fn _t_use_theme(cx: Scope) { fn _t_use_theme() {
use_theme(cx, Theme::dark); use_theme(Theme::dark);
} }
} }

View file

@ -1,28 +0,0 @@
use leptos::window;
use leptos_dom::ev;
use std::borrow::Cow;
use wasm_bindgen::{prelude::Closure, JsCast};
pub fn window_event_listener<E: ev::EventDescriptor + 'static>(
event: E,
cb: impl Fn(E::EventType) + 'static,
) -> impl FnOnce() -> ()
where
E::EventType: JsCast,
{
fn wel(
cb: Box<dyn FnMut(web_sys::Event)>,
event_name: Cow<'static, str>,
) -> impl FnOnce() -> () + 'static {
let cb = Closure::wrap(cb).into_js_value();
_ = window().add_event_listener_with_callback(&event_name, cb.unchecked_ref());
move || {
_ = window().remove_event_listener_with_callback(&event_name, cb.unchecked_ref());
}
}
wel(
Box::new(move |e| cb(e.unchecked_into::<E::EventType>())),
event.name(),
)
}

View file

@ -1,2 +1 @@
pub(crate) mod mount_style; pub(crate) mod mount_style;
pub mod dom;

View file

@ -3,13 +3,13 @@ use leptos::*;
use stylers::style_sheet_str; use stylers::style_sheet_str;
#[component] #[component]
pub fn Wave(cx: Scope, children: Children) -> impl IntoView { pub fn Wave(children: Children) -> impl IntoView {
let class_name = mount_style("wave", || style_sheet_str!("./src/wave/wave.css")); let class_name = mount_style("wave", || style_sheet_str!("./src/wave/wave.css"));
let (css_vars, set_css_vars) = create_signal(cx, String::new()); let (css_vars, set_css_vars) = create_signal(String::new());
let wave_ref = create_node_ref::<html::Div>(cx); let wave_ref = create_node_ref::<html::Div>();
wave_ref.on_load(cx, move |wave| { wave_ref.on_load(move |wave| {
wave.on(ev::mousedown, move |ev| { wave.on(ev::mousedown, move |ev| {
wave_ref.on_load(cx, move |wave| { wave_ref.on_load(move |wave| {
let rect = wave.get_bounding_client_rect(); let rect = wave.get_bounding_client_rect();
let client_x = f64::from(ev.client_x()); let client_x = f64::from(ev.client_x());
let client_y = f64::from(ev.client_y()); let client_y = f64::from(ev.client_y());
@ -22,9 +22,9 @@ pub fn Wave(cx: Scope, children: Children) -> impl IntoView {
}); });
}); });
view! { view! {
cx, class=class_name, class=class_name,
<div class="melt-wave" ref=wave_ref style=move || css_vars.get()> <div class="melt-wave" ref=wave_ref style=move || css_vars.get()>
{ children(cx) } { children() }
</div> </div>
} }
} }