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
[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" }
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"
icondata = { version = "0.0.7", features = [
"AiCloseOutlined",
@ -25,4 +25,4 @@ icondata = { version = "0.0.7", features = [
] }
[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
[dependencies]
leptos = { version = "0.4.8", features = ["csr"] }
leptos = { version = "0.5.0-beta2", features = ["csr"] }
melt-ui = { path = "../" }
icondata = { version = "0.0.7", features = [
"AiCloseOutlined",
"AiCheckOutlined",
] }
leptos_router = { version = "0.4.0", features = ["csr"] }
leptos_router = { version = "0.5.0-beta2", features = ["csr"] }
indoc = "2.0.1"
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"
public_url = "/melt-ui/"
dist = "../docs"
release = true
# release = true
[watch]
watch = [

View file

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

View file

@ -3,14 +3,14 @@ use leptos_router::use_navigate;
use melt_ui::*;
#[component]
pub fn SiteHeader(cx: Scope) -> impl IntoView {
view! { cx,
pub fn SiteHeader() -> impl IntoView {
view! {
<LayoutHeader
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 |_| {
let navigate = use_navigate(cx);
_ = navigate("/", Default::default());
let navigate = use_navigate();
navigate("/", Default::default());
}>
"Melt UI"
</span>

View file

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

View file

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

View file

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

View file

@ -5,11 +5,11 @@ 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 |_| {
pub fn ComponentsPage() -> impl IntoView {
let loaction = use_location();
let navigate = use_navigate();
let selected = create_rw_signal(String::from(""));
create_effect(move |_| {
let pathname = loaction.pathname.get();
let re = Regex::new(r"^/melt-ui/components/(.+)$").unwrap();
@ -23,14 +23,14 @@ pub fn ComponentsPage(cx: Scope) -> impl IntoView {
selected.set(path);
});
create_effect(cx, move |value| {
create_effect(move |value| {
let selected = selected.get();
if value.is_some() {
_ = navigate(&format!("/components/{selected}"), Default::default());
navigate(&format!("/components/{selected}"), Default::default());
}
selected
});
view! {cx,
view! {
<Layout position=LayoutPosition::ABSOLUTE>
<SiteHeader />
<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::*;
#[component]
pub fn Home(cx: Scope) -> impl IntoView {
let query_map = use_query_map(cx).get();
pub fn Home() -> impl IntoView {
let query_map = use_query_map().get_untracked();
if let Some(path) = query_map.get("path") {
let path = store_value(cx, path.clone());
request_animation_frame(move || {
let navigate = use_navigate(cx);
_ = navigate(&path.get_value(), Default::default());
});
let navigate = use_navigate();
navigate(path, Default::default());
}
view! { cx,
view! {
<Layout position=LayoutPosition::ABSOLUTE>
<SiteHeader />
<Layout position=LayoutPosition::ABSOLUTE style="top: 54px; display: flex; align-items: center; justify-content: center; flex-direction: column;">
<p>"A Leptos UI Library"</p>
<Button on:click=move |_| {
let navigate = use_navigate(cx);
_ = navigate("/components/menu", Default::default());
let navigate = use_navigate();
navigate("/components/menu", Default::default());
}>
"Read the docs"
</Button>

View file

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

View file

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

View file

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

View file

@ -1,8 +1,8 @@
use leptos::*;
#[component]
pub fn MobilePage(cx: Scope, path: &'static str) -> impl IntoView {
view! { cx,
pub fn MobilePage(path: &'static str) -> impl IntoView {
view! {
<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

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

View file

@ -2,18 +2,14 @@ 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"));
pub fn NavBarPage() -> impl IntoView {
let click_text = create_rw_signal(String::from("none"));
let click_left = SignalSetter::map(cx, move |_| {
click_text.set("left".to_string())
});
let click_left = SignalSetter::map(move |_| click_text.set("left".to_string()));
let click_right = SignalSetter::map(cx, move |_| {
click_text.set("right".to_string())
});
let click_right = SignalSetter::map(move |_| click_text.set("right".to_string()));
view! { cx,
view! {
<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">
@ -21,4 +17,4 @@ pub fn NavBarPage(cx: Scope) -> impl IntoView {
</div>
</div>
}
}
}

View file

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

View file

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

View file

@ -2,9 +2,9 @@ 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,
pub fn TabbarPage() -> impl IntoView {
let selected = create_rw_signal(String::from("o"));
view! {
<div style="height: 100vh; background: #f5f5f5">
{ move || selected.get() }
<Tabbar selected>
@ -13,10 +13,10 @@ pub fn TabbarPage(cx: Scope) -> impl IntoView {
</TabbarItem>
<TabbarItem name="i">
"if"
</TabbarItem>
</TabbarItem>
<TabbarItem name="o" icon=icondata::AiIcon::AiCloseOutlined>
"or"
</TabbarItem>
</TabbarItem>
</Tabbar>
</div>
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,31 +1,30 @@
// copy https://github.com/Carlosted/leptos-icons
// leptos updated version causes leptos_icons error
pub use icondata::*;
use leptos::SignalGet;
use leptos::*;
/// The Icon component.
#[leptos::component]
#[component]
pub fn Icon(
cx: leptos::Scope,
/// The icon to show.
#[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".
#[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".
#[prop(into, optional)]
height: Option<leptos::MaybeSignal<String>>,
height: Option<MaybeSignal<String>>,
/// HTML class attribute.
#[prop(into, optional)]
class: Option<leptos::MaybeSignal<String>>,
class: Option<MaybeSignal<String>>,
/// HTML style attribute.
#[prop(into, optional)]
style: Option<leptos::MaybeSignal<String>>,
) -> impl leptos::IntoView {
style: Option<MaybeSignal<String>>,
) -> impl IntoView {
let icon: IconData = icon.get().into();
let mut svg = leptos::svg::svg(cx);
let mut svg = svg::svg();
if let Some(classes) = class {
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.
svg = svg.attr(
"width",
leptos::Attribute::String(match (width, icon.width) {
(Some(a), Some(_b)) => std::borrow::Cow::from(a.get()),
(Some(a), None) => std::borrow::Cow::from(a.get()),
(None, Some(_b)) => std::borrow::Cow::from("1em"),
(None, None) => std::borrow::Cow::from("1em"),
Attribute::String(match (width, icon.width) {
(Some(a), Some(_b)) => Oco::from(a.get()),
(Some(a), None) => Oco::from(a.get()),
(None, Some(_b)) => Oco::from("1em"),
(None, None) => Oco::from("1em"),
}),
);
svg = svg.attr(
"height",
leptos::Attribute::String(match (height, icon.height) {
(Some(a), Some(_b)) => std::borrow::Cow::from(a.get()),
(Some(a), None) => std::borrow::Cow::from(a.get()),
(None, Some(_b)) => std::borrow::Cow::from("1em"),
(None, None) => std::borrow::Cow::from("1em"),
Attribute::String(match (height, icon.height) {
(Some(a), Some(_b)) => Oco::from(a.get()),
(Some(a), None) => Oco::from(a.get()),
(None, Some(_b)) => Oco::from("1em"),
(None, None) => Oco::from("1em"),
}),
);
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("role", "graphics-symbol");
svg = svg.inner_html(icon.data);
leptos::IntoView::into_view(svg, cx)
IntoView::into_view(svg)
}

View file

@ -1,9 +1,7 @@
use leptos::*;
#[component]
pub fn Image(
cx: Scope,
#[prop(optional, into)] src: MaybeSignal<String>,
#[prop(optional, into)] alt: 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)] object_fit: MaybeSignal<String>,
) -> impl IntoView {
let style = move || {
let mut style = String::new();
@ -24,7 +21,7 @@ pub fn Image(
if !height.is_empty() {
style.push_str(&format!("height: {height};"))
}
let border_radius = border_radius.get();
if !border_radius.is_empty() {
style.push_str(&format!("border-radius: {border_radius};"))
@ -33,7 +30,7 @@ pub fn Image(
style
};
view! {
cx,
<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]
pub fn Input(
cx: Scope,
#[prop(into)] value: RwSignal<String>,
#[prop(optional, into)] type_: MaybeSignal<InputType>,
) -> 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 input_ref = create_node_ref::<html::Input>(cx);
input_ref.on_load(cx, move |input| {
let input_ref = create_node_ref::<html::Input>();
input_ref.on_load(move |input| {
input.on(ev::input, move |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 theme = theme.get();
let border_color_hover = theme.common.color_primary.clone();
@ -49,7 +48,7 @@ pub fn Input(
css_vars
});
view! {
cx, class=class_name,
class=class_name,
<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"/>
</div>

View file

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

View file

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

View file

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

View file

@ -25,7 +25,6 @@ impl LayoutPosition {
#[component]
pub fn Layout(
cx: Scope,
#[prop(optional, into)] style: MaybeSignal<String>,
#[prop(optional)] position: LayoutPosition,
#[prop(optional, into)] has_sider: MaybeSignal<bool>,
@ -33,16 +32,16 @@ pub fn Layout(
) -> impl IntoView {
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();
if has_sider.get() {
style.push_str("display: flex; flex-wrap: nowrap; flex-direction: row; width: 100;%")
}
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()>
{ children(cx) }
{ children() }
</div>
}
}

View file

@ -5,18 +5,17 @@ use stylers::style_sheet_str;
#[component]
pub fn MenuItem(
cx: Scope,
#[prop(into)] key: MaybeSignal<&'static str>,
#[prop(into)] label: MaybeSignal<String>,
) -> impl IntoView {
let class_name = mount_style("menu-item", || style_sheet_str!("./src/menu/menu-item.css"));
let theme = use_theme(cx, Theme::light);
let menu = use_menu(cx);
let theme = use_theme(Theme::light);
let menu = use_menu();
let onclick_select = move |_| {
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 theme = theme.get();
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
});
view! {cx, class=class_name,
view! { class=class_name,
<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()>
{ move || label.get() }

View file

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

View file

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

View file

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

View file

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

View file

@ -9,16 +9,16 @@ pub struct ToastOptions {
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 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">
{ options.message }
</div>
};
let node = children.into_view(cx);
let node = children.into_view();
#[cfg(all(target_arch = "wasm32"))]
{
@ -32,4 +32,9 @@ pub fn show_toast(cx: Scope, options: ToastOptions) {
options.duration,
);
}
#[cfg(not(target_arch = "wasm32"))]
{
_ = parent;
_ = node;
}
}

View file

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

View file

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

View file

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

View file

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

View file

@ -3,11 +3,11 @@ use leptos::*;
use stylers::style_sheet_str;
#[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"));
view! {cx, class=class_name,
view! { class=class_name,
<table class="melt-table">
{children(cx)}
{children()}
</table>
}
}

View file

@ -5,18 +5,15 @@ use stylers::style_sheet_str;
pub use tab::*;
#[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 tab_options_vec = create_rw_signal(cx, vec![]);
provide_context(
cx,
TabsInjectionKey {
active_key: active_key.clone(),
tab_options_vec: tab_options_vec.clone(),
},
);
let theme = use_theme(cx, Theme::light);
let css_vars = create_memo(cx, move |_| {
let tab_options_vec = create_rw_signal(vec![]);
provide_context(TabsInjectionKey {
active_key: active_key.clone(),
tab_options_vec: tab_options_vec.clone(),
});
let theme = use_theme(Theme::light);
let css_vars = create_memo(move |_| {
let mut css_vars = String::new();
let theme = theme.get();
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
});
let label_line = create_rw_signal::<Option<TabsLabelLine>>(cx, None);
let label_line_style = create_memo(cx, move |_| {
let label_line = create_rw_signal::<Option<TabsLabelLine>>(None);
let label_line_style = create_memo(move |_| {
let mut style = String::new();
if let Some(line) = label_line.get() {
style.push_str(&format!("width: {}px; left: {}px", line.width, line.left))
}
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__label-list" ref=label_list_ref>
<For each=move || tab_options_vec.get() key=move |v| v.key.clone() view=move |cx, options| {
let label_ref = create_node_ref::<html::Span>(cx);
create_effect(cx, move |_| {
<For each=move || tab_options_vec.get() key=move |v| v.key.clone() view=move | options| {
let label_ref = create_node_ref::<html::Span>();
create_effect( move |_| {
let Some(label) = label_ref.get() else {
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())
on:click=move |_| active_key.set(options.key)
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>
</div>
<div>
{ children(cx) }
{ children() }
</div>
</div>
}
@ -102,6 +99,6 @@ impl TabsInjectionKey {
}
}
pub fn use_tabs(cx: Scope) -> TabsInjectionKey {
use_context::<TabsInjectionKey>(cx).expect("TabsInjectionKey not exist")
pub fn use_tabs() -> TabsInjectionKey {
use_context::<TabsInjectionKey>().expect("TabsInjectionKey not exist")
}

View file

@ -10,13 +10,13 @@ pub(crate) struct TabOptions {
}
#[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 tabs = use_tabs(cx);
let tabs = use_tabs();
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()) >
{ children(cx) }
{ children() }
</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
#[component]
pub fn Teleport(
cx: Scope,
#[prop(optional)] to: Option<&'static str>,
children: Children,
) -> impl IntoView {
pub fn Teleport(#[prop(optional)] to: Option<&'static str>, children: Children) -> impl IntoView {
let parent = if let Some(to) = to {
document()
.query_selector(to)
@ -20,16 +16,15 @@ pub fn Teleport(
#[cfg(all(target_arch = "wasm32"))]
{
use leptos_dom::Mountable;
let node = children(cx).into_view(cx);
let node = children().into_view();
parent.append_child(&node.get_mountable_node()).unwrap();
}
#[cfg(not(target_arch = "wasm32"))]
{
_ = cx;
_ = parent;
_ = children;
}
view! { cx, <></> }
view! { <></> }
}

View file

@ -31,24 +31,20 @@ impl CommonTheme {
fn common() -> 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(),
color_primary: "".into(),
color_success: "".into(),
color_warning: "".into(),
color_error: "".into(),
font_size: "14px".into(),
font_size_small: "12px".into(),
font_size_medium: "16px".into(),
font_size_large: "20px".into(),
font_size_huge: "24px".into(),
line_height: "22px".into(),
line_height_small: "20px".into(),
line_height_medium: "24px".into(),
line_height_large: "28px".into(),
line_height_huge: "32px".into(),
border_radius: "3px".into(),
border_radius_small: "2px".into(),
border_radius_medium: "4px".into(),
@ -76,4 +72,4 @@ impl ThemeMethod for CommonTheme {
..CommonTheme::common()
}
}
}
}

View file

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

View file

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