mirror of
https://github.com/yewprint/yewprint
synced 2024-11-22 03:23:03 +00:00
Add components Portal and Overlay (#161)
This commit is contained in:
parent
b6a6004fcf
commit
ba9b1746f4
19 changed files with 591 additions and 257 deletions
202
Cargo.lock
generated
202
Cargo.lock
generated
|
@ -17,15 +17,6 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "android_system_properties"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.66"
|
version = "1.0.66"
|
||||||
|
@ -105,17 +96,6 @@ version = "2.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
|
checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "build-data"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a94f9f7aab679acac7ce29ba5581c00d3971a861c3b501c5bb74c3ba0026d90"
|
|
||||||
dependencies = [
|
|
||||||
"chrono 0.4.23",
|
|
||||||
"safe-lock",
|
|
||||||
"safe-regex",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.11.1"
|
version = "3.11.1"
|
||||||
|
@ -194,21 +174,6 @@ dependencies = [
|
||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "chrono"
|
|
||||||
version = "0.4.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
|
||||||
dependencies = [
|
|
||||||
"iana-time-zone",
|
|
||||||
"js-sys",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits 0.2.15",
|
|
||||||
"time",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chunked_transfer"
|
name = "chunked_transfer"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -261,16 +226,6 @@ dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "codespan-reporting"
|
|
||||||
version = "0.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
|
||||||
dependencies = [
|
|
||||||
"termcolor",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console_error_panic_hook"
|
name = "console_error_panic_hook"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
@ -281,12 +236,6 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-foundation-sys"
|
|
||||||
version = "0.8.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
|
@ -339,50 +288,6 @@ dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxx"
|
|
||||||
version = "1.0.83"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"cxxbridge-flags",
|
|
||||||
"cxxbridge-macro",
|
|
||||||
"link-cplusplus",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxx-build"
|
|
||||||
version = "1.0.83"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"codespan-reporting",
|
|
||||||
"once_cell",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"scratch",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxxbridge-flags"
|
|
||||||
version = "1.0.83"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cxxbridge-macro"
|
|
||||||
version = "1.0.83"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
|
@ -784,30 +689,6 @@ version = "2.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone"
|
|
||||||
version = "0.1.53"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
|
|
||||||
dependencies = [
|
|
||||||
"android_system_properties",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"iana-time-zone-haiku",
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "iana-time-zone-haiku"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
|
||||||
dependencies = [
|
|
||||||
"cxx",
|
|
||||||
"cxx-build",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "id-arena"
|
name = "id-arena"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
|
@ -975,15 +856,6 @@ version = "0.2.138"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "link-cplusplus"
|
|
||||||
version = "1.0.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
@ -1226,7 +1098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "478cc5188290e4dc1fa99a3128705c325c569da6c5ca67621a47afb9bcaa00ea"
|
checksum = "478cc5188290e4dc1fa99a3128705c325c569da6c5ca67621a47afb9bcaa00ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 0.5.3",
|
"byteorder 0.5.3",
|
||||||
"chrono 0.2.25",
|
"chrono",
|
||||||
"rustc-serialize",
|
"rustc-serialize",
|
||||||
"serde 0.7.15",
|
"serde 0.7.15",
|
||||||
"xml-rs",
|
"xml-rs",
|
||||||
|
@ -1436,59 +1308,6 @@ version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe-lock"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "077d73db7973cccf63eb4aff1e5a34dc2459baa867512088269ea5f2f4253c90"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe-proc-macro2"
|
|
||||||
version = "1.0.36"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "814c536dcd27acf03296c618dab7ad62d28e70abd7ba41d3f34a2ce707a2c666"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe-quote"
|
|
||||||
version = "1.0.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77e530f7831f3feafcd5f1aae406ac205dd998436b4007c8e80f03eca78a88f7"
|
|
||||||
dependencies = [
|
|
||||||
"safe-proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe-regex"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a15289bf322e0673d52756a18194167f2378ec1a15fe884af6e2d2cb934822b0"
|
|
||||||
dependencies = [
|
|
||||||
"safe-regex-macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe-regex-compiler"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fba76fae590a2aa665279deb1f57b5098cbace01a0c5e60e262fcf55f7c51542"
|
|
||||||
dependencies = [
|
|
||||||
"safe-proc-macro2",
|
|
||||||
"safe-quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "safe-regex-macro"
|
|
||||||
version = "0.2.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "96c2e96b5c03f158d1b16ba79af515137795f4ad4e8de3f790518aae91f1d127"
|
|
||||||
dependencies = [
|
|
||||||
"safe-proc-macro2",
|
|
||||||
"safe-regex-compiler",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "safemem"
|
name = "safemem"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -1510,12 +1329,6 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scratch"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sct"
|
name = "sct"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -1813,18 +1626,6 @@ version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -2459,7 +2260,6 @@ dependencies = [
|
||||||
name = "yewprint-doc"
|
name = "yewprint-doc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"build-data",
|
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"gloo",
|
"gloo",
|
||||||
"implicit-clone",
|
"implicit-clone",
|
||||||
|
|
|
@ -22,7 +22,7 @@ gloo = "0.8"
|
||||||
id_tree = { version = "1.8", optional = true }
|
id_tree = { version = "1.8", optional = true }
|
||||||
implicit-clone = "0.3.5"
|
implicit-clone = "0.3.5"
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
web-sys = { version = "0.3", features = ["DomRect", "Element", "Event", "HtmlSelectElement"] }
|
web-sys = { version = "0.3", features = ["DomRect", "Element", "Event", "HtmlSelectElement", "DomTokenList"] }
|
||||||
yew = "0.20"
|
yew = "0.20"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
|
@ -100,9 +100,9 @@ Roadmap
|
||||||
- [x] [InputGroup](https://blueprintjs.com/docs/#core/components/text-inputs.input-group)
|
- [x] [InputGroup](https://blueprintjs.com/docs/#core/components/text-inputs.input-group)
|
||||||
- [x] [TextArea](https://blueprintjs.com/docs/#core/components/text-inputs.text-area)
|
- [x] [TextArea](https://blueprintjs.com/docs/#core/components/text-inputs.text-area)
|
||||||
- [ ] [TagInput](https://blueprintjs.com/docs/#core/components/tag-input)
|
- [ ] [TagInput](https://blueprintjs.com/docs/#core/components/tag-input)
|
||||||
- [ ] [Overlay](https://blueprintjs.com/docs/#core/components/overlay)
|
- [x] [Overlay](https://blueprintjs.com/docs/#core/components/overlay)
|
||||||
- depends on: Portal
|
- depends on: Portal
|
||||||
- [ ] [Portal](https://blueprintjs.com/docs/#core/components/portal)
|
- [x] [Portal](https://blueprintjs.com/docs/#core/components/portal)
|
||||||
- [ ] [Alert](https://blueprintjs.com/docs/#core/components/alert)
|
- [ ] [Alert](https://blueprintjs.com/docs/#core/components/alert)
|
||||||
- depends on: Button, Dialog
|
- depends on: Button, Dialog
|
||||||
- [ ] [Context menu](https://blueprintjs.com/docs/#core/components/context-menu)
|
- [ ] [Context menu](https://blueprintjs.com/docs/#core/components/context-menu)
|
||||||
|
|
|
@ -23,6 +23,8 @@ pub struct ButtonProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub icon: Option<Icon>,
|
pub icon: Option<Icon>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
pub right_icon: Option<Icon>,
|
||||||
|
#[prop_or_default]
|
||||||
pub intent: Option<Intent>,
|
pub intent: Option<Intent>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub title: Option<AttrValue>,
|
pub title: Option<AttrValue>,
|
||||||
|
@ -33,6 +35,8 @@ pub struct ButtonProps {
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub style: Option<AttrValue>,
|
pub style: Option<AttrValue>,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
|
pub button_ref: NodeRef,
|
||||||
|
#[prop_or_default]
|
||||||
pub children: Children,
|
pub children: Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,11 +52,13 @@ pub fn button(props: &ButtonProps) -> Html {
|
||||||
active,
|
active,
|
||||||
disabled,
|
disabled,
|
||||||
icon,
|
icon,
|
||||||
|
right_icon,
|
||||||
intent,
|
intent,
|
||||||
title,
|
title,
|
||||||
onclick,
|
onclick,
|
||||||
class,
|
class,
|
||||||
style,
|
style,
|
||||||
|
button_ref,
|
||||||
children,
|
children,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
@ -74,6 +80,7 @@ pub fn button(props: &ButtonProps) -> Html {
|
||||||
{style}
|
{style}
|
||||||
{title}
|
{title}
|
||||||
onclick={(!disabled).then_some(onclick.clone())}
|
onclick={(!disabled).then_some(onclick.clone())}
|
||||||
|
ref={button_ref.clone()}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
loading
|
loading
|
||||||
|
@ -85,7 +92,6 @@ pub fn button(props: &ButtonProps) -> Html {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
<Icon {icon} />
|
<Icon {icon} />
|
||||||
//{icon.map(|icon| html!(<Icon {icon} />))}
|
|
||||||
{
|
{
|
||||||
(!children.is_empty())
|
(!children.is_empty())
|
||||||
.then(|| html! {
|
.then(|| html! {
|
||||||
|
@ -94,6 +100,7 @@ pub fn button(props: &ButtonProps) -> Html {
|
||||||
</span>
|
</span>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
<Icon icon={right_icon} />
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct CardProps {
|
||||||
#[prop_or(false)]
|
#[prop_or(false)]
|
||||||
pub interactive: bool,
|
pub interactive: bool,
|
||||||
#[prop_or_default]
|
#[prop_or_default]
|
||||||
pub style: AttrValue,
|
pub style: Option<AttrValue>,
|
||||||
pub children: Children,
|
pub children: Children,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ impl IconSize {
|
||||||
pub const LARGE: IconSize = IconSize(20.0);
|
pub const LARGE: IconSize = IconSize(20.0);
|
||||||
|
|
||||||
pub fn as_f64(&self) -> f64 {
|
pub fn as_f64(&self) -> f64 {
|
||||||
self.0 as f64
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_f32(&self) -> f32 {
|
pub fn as_f32(&self) -> f32 {
|
||||||
|
|
|
@ -20,7 +20,9 @@ mod icon;
|
||||||
mod input_group;
|
mod input_group;
|
||||||
mod menu;
|
mod menu;
|
||||||
mod numeric_input;
|
mod numeric_input;
|
||||||
|
mod overlay;
|
||||||
mod panel_stack;
|
mod panel_stack;
|
||||||
|
mod portal;
|
||||||
mod progress_bar;
|
mod progress_bar;
|
||||||
mod radio;
|
mod radio;
|
||||||
mod radio_group;
|
mod radio_group;
|
||||||
|
@ -50,7 +52,9 @@ pub use id_tree;
|
||||||
pub use input_group::*;
|
pub use input_group::*;
|
||||||
pub use menu::*;
|
pub use menu::*;
|
||||||
pub use numeric_input::*;
|
pub use numeric_input::*;
|
||||||
|
pub use overlay::*;
|
||||||
pub use panel_stack::*;
|
pub use panel_stack::*;
|
||||||
|
pub use portal::*;
|
||||||
pub use progress_bar::*;
|
pub use progress_bar::*;
|
||||||
pub use radio::*;
|
pub use radio::*;
|
||||||
pub use radio_group::*;
|
pub use radio_group::*;
|
||||||
|
|
275
src/overlay.rs
Normal file
275
src/overlay.rs
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
use crate::Portal;
|
||||||
|
use gloo::timers::callback::Timeout;
|
||||||
|
use wasm_bindgen::closure::Closure;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use web_sys::{Element, HtmlElement, NodeList};
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// - use without <Portal/>
|
||||||
|
// - enforce focus inside the overlay
|
||||||
|
// - CSS transitions
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Overlay {
|
||||||
|
start_focus_trap: NodeRef,
|
||||||
|
content_ref: NodeRef,
|
||||||
|
callback_timeout: Option<Timeout>,
|
||||||
|
initial_open: bool,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
document_focus_closure: Closure<dyn FnMut(FocusEvent)>,
|
||||||
|
last_active_element: Option<Element>,
|
||||||
|
focus_first_element_closure: Closure<dyn FnMut()>,
|
||||||
|
focus_last_element_closure: Closure<dyn FnMut()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Properties)]
|
||||||
|
pub struct OverlayProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub class: Classes,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub style: Option<AttrValue>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub open: bool,
|
||||||
|
#[prop_or(true)]
|
||||||
|
pub backdrop: bool,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub onclose: Callback<()>,
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: Children,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Msg {
|
||||||
|
OnKeyDown(KeyboardEvent),
|
||||||
|
OnClick(MouseEvent),
|
||||||
|
FocusFirstElement,
|
||||||
|
FocusLastElement,
|
||||||
|
Close,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Overlay {
|
||||||
|
type Properties = OverlayProps;
|
||||||
|
type Message = Msg;
|
||||||
|
|
||||||
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
|
let content_ref = NodeRef::default();
|
||||||
|
|
||||||
|
let document_focus_closure = {
|
||||||
|
let callback = ctx.link().callback(|_| Msg::FocusFirstElement);
|
||||||
|
let content_ref = content_ref.clone();
|
||||||
|
Closure::new(Box::new(move |_event| {
|
||||||
|
let active_element_in_content = content_ref
|
||||||
|
.cast::<Element>()
|
||||||
|
.map(|content| {
|
||||||
|
content.contains(gloo::utils::document().active_element().as_deref())
|
||||||
|
})
|
||||||
|
.unwrap_or(false);
|
||||||
|
if !active_element_in_content {
|
||||||
|
callback.emit(());
|
||||||
|
}
|
||||||
|
}) as Box<dyn FnMut(_)>)
|
||||||
|
};
|
||||||
|
gloo::utils::document().set_onfocus(Some(document_focus_closure.as_ref().unchecked_ref()));
|
||||||
|
|
||||||
|
let focus_first_element_closure = {
|
||||||
|
let content_ref = content_ref.clone();
|
||||||
|
Closure::new(Box::new(move || {
|
||||||
|
if let Some(element) = get_focusable_elements(&content_ref)
|
||||||
|
.and_then(|x| x.item(0))
|
||||||
|
.and_then(|x| x.dyn_into::<HtmlElement>().ok())
|
||||||
|
{
|
||||||
|
element.focus().unwrap();
|
||||||
|
}
|
||||||
|
}) as Box<dyn FnMut()>)
|
||||||
|
};
|
||||||
|
|
||||||
|
let focus_last_element_closure = {
|
||||||
|
let content_ref = content_ref.clone();
|
||||||
|
Closure::new(Box::new(move || {
|
||||||
|
if let Some(element) = get_focusable_elements(&content_ref)
|
||||||
|
.and_then(|x| x.item(x.length() - 1))
|
||||||
|
.and_then(|x| x.dyn_into::<HtmlElement>().ok())
|
||||||
|
{
|
||||||
|
element.focus().unwrap();
|
||||||
|
}
|
||||||
|
}) as Box<dyn FnMut()>)
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
start_focus_trap: NodeRef::default(),
|
||||||
|
content_ref,
|
||||||
|
callback_timeout: None,
|
||||||
|
initial_open: false,
|
||||||
|
document_focus_closure,
|
||||||
|
last_active_element: None,
|
||||||
|
focus_first_element_closure,
|
||||||
|
focus_last_element_closure,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool {
|
||||||
|
let new_props = ctx.props();
|
||||||
|
|
||||||
|
if new_props.open != old_props.open {
|
||||||
|
self.initial_open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_props.open {
|
||||||
|
self.last_active_element = gloo::utils::document().active_element();
|
||||||
|
gloo::utils::body()
|
||||||
|
.class_list()
|
||||||
|
.add_1("bp3-overlay-open")
|
||||||
|
.unwrap();
|
||||||
|
} else {
|
||||||
|
gloo::utils::body()
|
||||||
|
.class_list()
|
||||||
|
.remove_1("bp3-overlay-open")
|
||||||
|
.unwrap();
|
||||||
|
if let Some(element) = self
|
||||||
|
.last_active_element
|
||||||
|
.take()
|
||||||
|
.and_then(|x| x.dyn_into::<HtmlElement>().ok())
|
||||||
|
{
|
||||||
|
let _ = element.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
|
match msg {
|
||||||
|
Msg::OnKeyDown(event) => {
|
||||||
|
if event.key() == "Escape" {
|
||||||
|
ctx.props().onclose.emit(());
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Msg::OnClick(_event) => {
|
||||||
|
if self.callback_timeout.is_none() {
|
||||||
|
let callback = ctx.link().callback(|_| Msg::Close);
|
||||||
|
self.callback_timeout
|
||||||
|
.replace(Timeout::new(0, move || callback.emit(())));
|
||||||
|
} else {
|
||||||
|
self.callback_timeout.take();
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Msg::FocusFirstElement => {
|
||||||
|
// always delay focus manipulation to just before repaint to prevent scroll jumping
|
||||||
|
gloo::utils::window()
|
||||||
|
.request_animation_frame(
|
||||||
|
self.focus_first_element_closure.as_ref().unchecked_ref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Msg::FocusLastElement => {
|
||||||
|
// always delay focus manipulation to just before repaint to prevent scroll jumping
|
||||||
|
gloo::utils::window()
|
||||||
|
.request_animation_frame(
|
||||||
|
self.focus_last_element_closure.as_ref().unchecked_ref(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Msg::Close => {
|
||||||
|
self.callback_timeout.take();
|
||||||
|
ctx.props().onclose.emit(());
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let Self::Properties {
|
||||||
|
class,
|
||||||
|
style,
|
||||||
|
open,
|
||||||
|
backdrop,
|
||||||
|
onclose: _,
|
||||||
|
children,
|
||||||
|
} = ctx.props();
|
||||||
|
|
||||||
|
let backdrop = backdrop.then(|| {
|
||||||
|
html! {
|
||||||
|
<div class="bp3-overlay-backdrop" />
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let inner = open.then(|| {
|
||||||
|
html! {
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
class="bp3-overlay-start-focus-trap"
|
||||||
|
ref={self.start_focus_trap.clone()}
|
||||||
|
tabindex=0
|
||||||
|
// NOTE: I am not 100% sure this is correct. In Blueprint they capture the
|
||||||
|
// Shift+Tab combination but it looks like it's more for historic
|
||||||
|
// reason... well, it seems to work on current Chrome and Firefox so...
|
||||||
|
onfocus={ctx.link().callback(|_| Msg::FocusLastElement)}
|
||||||
|
/>
|
||||||
|
{backdrop}
|
||||||
|
<div
|
||||||
|
class={classes!("bp3-overlay-content", class.clone())}
|
||||||
|
{style}
|
||||||
|
ref={self.content_ref.clone()}
|
||||||
|
onclick={ctx.link().callback(Msg::OnClick)}
|
||||||
|
>
|
||||||
|
{for children.iter()}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="bp3-overlay-end-focus-trap"
|
||||||
|
ref={self.start_focus_trap.clone()}
|
||||||
|
tabindex=0
|
||||||
|
onfocus={ctx.link().callback(|_| Msg::FocusFirstElement)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<Portal>
|
||||||
|
<div
|
||||||
|
class={classes!(
|
||||||
|
"bp3-overlay",
|
||||||
|
"bp3-overlay-scroll-container",
|
||||||
|
open.then_some("bp3-overlay-open"),
|
||||||
|
)}
|
||||||
|
aria-live="polite"
|
||||||
|
onkeydown={ctx.link().callback(Msg::OnKeyDown)}
|
||||||
|
onclick={ctx.link().callback(Msg::OnClick)}
|
||||||
|
>
|
||||||
|
{inner}
|
||||||
|
</div>
|
||||||
|
</Portal>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rendered(&mut self, ctx: &Context<Self>, _first_render: bool) {
|
||||||
|
let Self::Properties { open, .. } = ctx.props();
|
||||||
|
|
||||||
|
if *open && !self.initial_open {
|
||||||
|
self.initial_open = true;
|
||||||
|
ctx.link().send_message(Msg::FocusFirstElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Overlay {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
gloo::utils::document().set_onfocus(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_focusable_elements(node_ref: &NodeRef) -> Option<NodeList> {
|
||||||
|
node_ref.cast::<Element>().and_then(|element| {
|
||||||
|
element
|
||||||
|
.query_selector_all(
|
||||||
|
"a[href]:not([tabindex=\"-1\"]),button:not([disabled]):not([tabindex=\"-1\"]),\
|
||||||
|
details:not([tabindex=\"-1\"]),input:not([disabled]):not([tabindex=\"-1\"]),\
|
||||||
|
select:not([disabled]):not([tabindex=\"-1\"]),\
|
||||||
|
textarea:not([disabled]):not([tabindex=\"-1\"]),[tabindex]:not([tabindex=\"-1\"])",
|
||||||
|
)
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
}
|
56
src/portal.rs
Normal file
56
src/portal.rs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
use web_sys::Element;
|
||||||
|
use yew::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Portal {
|
||||||
|
container_element: Option<Element>,
|
||||||
|
node_ref: NodeRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Properties)]
|
||||||
|
pub struct PortalProps {
|
||||||
|
#[prop_or_default]
|
||||||
|
pub children: Children,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Portal {
|
||||||
|
type Properties = PortalProps;
|
||||||
|
type Message = ();
|
||||||
|
|
||||||
|
fn create(_: &Context<Self>) -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let contents = self
|
||||||
|
.container_element
|
||||||
|
.clone()
|
||||||
|
.map(|container_element| {
|
||||||
|
create_portal(
|
||||||
|
html! {
|
||||||
|
{for ctx.props().children.iter()}
|
||||||
|
},
|
||||||
|
container_element,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div ref={self.node_ref.clone()}>
|
||||||
|
{contents}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
|
||||||
|
if first_render {
|
||||||
|
let container_element = gloo::utils::document().create_element("div").unwrap();
|
||||||
|
container_element.set_class_name("bp3-portal");
|
||||||
|
gloo::utils::body()
|
||||||
|
.append_child(&container_element)
|
||||||
|
.unwrap();
|
||||||
|
self.container_element.replace(container_element);
|
||||||
|
ctx.link().send_message(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,9 +26,7 @@ pub fn progress_bar(
|
||||||
}: &ProgressBarProps,
|
}: &ProgressBarProps,
|
||||||
) -> Html {
|
) -> Html {
|
||||||
let style = if let Some(value) = value {
|
let style = if let Some(value) = value {
|
||||||
// NOTE: nightly, issue #44095 for f32::clamp
|
let percent = value * 100.0;
|
||||||
// let percent = ((1000. * value).ceil() / 10.).clamp(0.,100.);
|
|
||||||
let percent = ((1000. * value).ceil() / 10.).max(0.).min(100.);
|
|
||||||
AttrValue::from(format!("width: {}%;", percent))
|
AttrValue::from(format!("width: {}%;", percent))
|
||||||
} else {
|
} else {
|
||||||
"".into()
|
"".into()
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub(crate) fn generate_icons() -> Result<()> {
|
||||||
src.push_str("];\n");
|
src.push_str("];\n");
|
||||||
src.push('}');
|
src.push('}');
|
||||||
|
|
||||||
fs::write(&dest_path, src).context("could not write into file")?;
|
fs::write(dest_path, src).context("could not write into file")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ fn download_css(force: bool) -> Result<()> {
|
||||||
"@blueprintjs/docs-theme",
|
"@blueprintjs/docs-theme",
|
||||||
"3.11.1",
|
"3.11.1",
|
||||||
Path::new("package/lib/css/docs-theme.css"),
|
Path::new("package/lib/css/docs-theme.css"),
|
||||||
&static_path.join("docs-theme.css"),
|
static_path.join("docs-theme.css"),
|
||||||
)
|
)
|
||||||
.context("while downloading CSS of @blueprintjs/docs-theme")?;
|
.context("while downloading CSS of @blueprintjs/docs-theme")?;
|
||||||
log::info!("Docs Theme CSS updated to: {}", version);
|
log::info!("Docs Theme CSS updated to: {}", version);
|
||||||
|
|
|
@ -30,7 +30,6 @@ yew-router = "0.17"
|
||||||
yewprint = { path = ".." }
|
yewprint = { path = ".." }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
build-data = "0.1.3"
|
|
||||||
syntect = "0.5.0"
|
syntect = "0.5.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -10,8 +10,6 @@ fn main() {
|
||||||
let theme_set = ThemeSet::load_defaults();
|
let theme_set = ThemeSet::load_defaults();
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
||||||
build_data::set_GIT_BRANCH();
|
|
||||||
|
|
||||||
fn recursive<P: AsRef<Path>>(
|
fn recursive<P: AsRef<Path>>(
|
||||||
base_path: P,
|
base_path: P,
|
||||||
syntax_set: &SyntaxSet,
|
syntax_set: &SyntaxSet,
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::icon::*;
|
||||||
use crate::input_group::*;
|
use crate::input_group::*;
|
||||||
use crate::menu::*;
|
use crate::menu::*;
|
||||||
use crate::numeric_input::*;
|
use crate::numeric_input::*;
|
||||||
|
use crate::overlay::*;
|
||||||
use crate::panel_stack::*;
|
use crate::panel_stack::*;
|
||||||
use crate::progress_bar::*;
|
use crate::progress_bar::*;
|
||||||
use crate::radio::*;
|
use crate::radio::*;
|
||||||
|
@ -22,6 +23,7 @@ use crate::tag::*;
|
||||||
use crate::text::*;
|
use crate::text::*;
|
||||||
use crate::text_area::*;
|
use crate::text_area::*;
|
||||||
use crate::tree::*;
|
use crate::tree::*;
|
||||||
|
use crate::DARK;
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::prelude::*;
|
use yew_router::prelude::*;
|
||||||
use yewprint::{Icon, Menu, MenuItem};
|
use yewprint::{Icon, Menu, MenuItem};
|
||||||
|
@ -35,9 +37,7 @@ pub fn app_root() -> Html {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App;
|
||||||
dark_theme: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
ToggleLight,
|
ToggleLight,
|
||||||
|
@ -49,17 +49,14 @@ impl Component for App {
|
||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_ctx: &Context<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
App {
|
Self
|
||||||
dark_theme: web_sys::window()
|
|
||||||
.and_then(|x| x.match_media("(prefers-color-scheme: dark)").ok().flatten())
|
|
||||||
.map(|x| x.matches())
|
|
||||||
.unwrap_or(true),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::ToggleLight => self.dark_theme ^= true,
|
Msg::ToggleLight => {
|
||||||
|
DARK.with(|x| x.replace(!*x.borrow()));
|
||||||
|
}
|
||||||
Msg::GoToMenu(event, doc_menu) => {
|
Msg::GoToMenu(event, doc_menu) => {
|
||||||
event.prevent_default();
|
event.prevent_default();
|
||||||
if let Some(navigator) = ctx.link().navigator() {
|
if let Some(navigator) = ctx.link().navigator() {
|
||||||
|
@ -73,21 +70,15 @@ impl Component for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
let netlify_badge = if self.dark_theme {
|
let dark = DARK.with(|x| *x.borrow());
|
||||||
|
|
||||||
|
let netlify_badge = if dark {
|
||||||
"https://www.netlify.com/img/global/badges/netlify-color-accent.svg"
|
"https://www.netlify.com/img/global/badges/netlify-color-accent.svg"
|
||||||
} else {
|
} else {
|
||||||
"https://www.netlify.com/img/global/badges/netlify-color-bg.svg"
|
"https://www.netlify.com/img/global/badges/netlify-color-bg.svg"
|
||||||
};
|
};
|
||||||
let go_to_theme_label = if self.dark_theme {
|
let go_to_theme_label = if dark { "Light theme" } else { "Dark theme" };
|
||||||
"Light theme"
|
let go_to_theme_icon = if dark { Icon::Flash } else { Icon::Moon };
|
||||||
} else {
|
|
||||||
"Dark theme"
|
|
||||||
};
|
|
||||||
let go_to_theme_icon = if self.dark_theme {
|
|
||||||
Icon::Flash
|
|
||||||
} else {
|
|
||||||
Icon::Moon
|
|
||||||
};
|
|
||||||
|
|
||||||
let menu = html! {
|
let menu = html! {
|
||||||
<Menu>
|
<Menu>
|
||||||
|
@ -175,6 +166,12 @@ impl Component for App {
|
||||||
onclick={ctx.link()
|
onclick={ctx.link()
|
||||||
.callback(|e| Msg::GoToMenu(e, DocMenu::NumericInput))}
|
.callback(|e| Msg::GoToMenu(e, DocMenu::NumericInput))}
|
||||||
/>
|
/>
|
||||||
|
<MenuItem
|
||||||
|
text={html!("Overlay")}
|
||||||
|
href="/overlay"
|
||||||
|
onclick={ctx.link()
|
||||||
|
.callback(|e| Msg::GoToMenu(e, DocMenu::Overlay))}
|
||||||
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
text={html!("PanelStack")}
|
text={html!("PanelStack")}
|
||||||
href="/panel-stack"
|
href="/panel-stack"
|
||||||
|
@ -279,7 +276,7 @@ impl Component for App {
|
||||||
};
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<div class={classes!("docs-root", self.dark_theme.then_some("bp3-dark"))}>
|
<div class={classes!("docs-root", dark.then_some("bp3-dark"))}>
|
||||||
<div class={classes!("docs-app")}>
|
<div class={classes!("docs-app")}>
|
||||||
{{ navigation }}
|
{{ navigation }}
|
||||||
<main class={classes!("docs-content-wrapper")} role="main">
|
<main class={classes!("docs-content-wrapper")} role="main">
|
||||||
|
@ -308,6 +305,7 @@ fn switch(route: DocMenu) -> Html {
|
||||||
DocMenu::InputGroup => html!(<InputGroupDoc />),
|
DocMenu::InputGroup => html!(<InputGroupDoc />),
|
||||||
DocMenu::Menu => html!(<MenuDoc />),
|
DocMenu::Menu => html!(<MenuDoc />),
|
||||||
DocMenu::NumericInput => html!(<NumericInputDoc />),
|
DocMenu::NumericInput => html!(<NumericInputDoc />),
|
||||||
|
DocMenu::Overlay => html!(<OverlayDoc />),
|
||||||
DocMenu::PanelStack => html!(<PanelStackDoc />),
|
DocMenu::PanelStack => html!(<PanelStackDoc />),
|
||||||
DocMenu::ProgressBar => html!(<ProgressBarDoc />),
|
DocMenu::ProgressBar => html!(<ProgressBarDoc />),
|
||||||
DocMenu::Radio => html!(<RadioDoc />),
|
DocMenu::Radio => html!(<RadioDoc />),
|
||||||
|
@ -350,6 +348,8 @@ pub enum DocMenu {
|
||||||
Menu,
|
Menu,
|
||||||
#[at("/numeric-input")]
|
#[at("/numeric-input")]
|
||||||
NumericInput,
|
NumericInput,
|
||||||
|
#[at("/overlay")]
|
||||||
|
Overlay,
|
||||||
#[at("/panel-stack")]
|
#[at("/panel-stack")]
|
||||||
PanelStack,
|
PanelStack,
|
||||||
#[at("/progress-bar")]
|
#[at("/progress-bar")]
|
||||||
|
|
|
@ -23,6 +23,7 @@ mod input_group;
|
||||||
mod logo;
|
mod logo;
|
||||||
mod menu;
|
mod menu;
|
||||||
mod numeric_input;
|
mod numeric_input;
|
||||||
|
mod overlay;
|
||||||
mod panel_stack;
|
mod panel_stack;
|
||||||
mod progress_bar;
|
mod progress_bar;
|
||||||
mod radio;
|
mod radio;
|
||||||
|
@ -38,6 +39,16 @@ mod tree;
|
||||||
pub use app::*;
|
pub use app::*;
|
||||||
pub use example::*;
|
pub use example::*;
|
||||||
pub use logo::*;
|
pub use logo::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
pub static DARK: RefCell<bool> = {
|
||||||
|
RefCell::new(web_sys::window()
|
||||||
|
.and_then(|x| x.match_media("(prefers-color-scheme: dark)").ok().flatten())
|
||||||
|
.map(|x| x.matches())
|
||||||
|
.unwrap_or(true))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! include_raw_html {
|
macro_rules! include_raw_html {
|
||||||
|
@ -67,7 +78,7 @@ macro_rules! build_source_code_component {
|
||||||
pub fn generate_url() -> String {
|
pub fn generate_url() -> String {
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
let component_name = Path::new(file!())
|
let component = Path::new(file!())
|
||||||
.parent()
|
.parent()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.file_name()
|
.file_name()
|
||||||
|
@ -75,10 +86,13 @@ macro_rules! build_source_code_component {
|
||||||
.to_str()
|
.to_str()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
format!(
|
if let (Some(actor), Some(branch)) =
|
||||||
"https://github.com/yewprint/yewprint/blob/HEAD/src/{}.rs",
|
(option_env!("GITHUB_ACTOR"), option_env!("GITHUB_HEAD_REF"))
|
||||||
component_name,
|
{
|
||||||
)
|
format!("https://github.com/{actor}/yewprint/blob/{branch}/src/{component}.rs")
|
||||||
|
} else {
|
||||||
|
format!("https://github.com/yewprint/yewprint/blob/HEAD/src/{component}.rs")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
100
yewprint-doc/src/overlay/example.rs
Normal file
100
yewprint-doc/src/overlay/example.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
use crate::DARK;
|
||||||
|
use yew::prelude::*;
|
||||||
|
use yewprint::{Button, Card, Elevation, Icon, Intent, Overlay, H3};
|
||||||
|
|
||||||
|
pub struct Example {
|
||||||
|
open: bool,
|
||||||
|
tall: bool,
|
||||||
|
show_button_ref: NodeRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Properties)]
|
||||||
|
pub struct ExampleProps {
|
||||||
|
pub backdrop: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Msg {
|
||||||
|
Open,
|
||||||
|
Close,
|
||||||
|
ToggleTall,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Example {
|
||||||
|
type Message = Msg;
|
||||||
|
type Properties = ExampleProps;
|
||||||
|
|
||||||
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
|
Example {
|
||||||
|
open: false,
|
||||||
|
tall: false,
|
||||||
|
show_button_ref: NodeRef::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
|
match msg {
|
||||||
|
Msg::Open => {
|
||||||
|
self.open = true;
|
||||||
|
}
|
||||||
|
Msg::Close => {
|
||||||
|
self.open = false;
|
||||||
|
}
|
||||||
|
Msg::ToggleTall => {
|
||||||
|
self.tall ^= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let Self::Properties { backdrop } = &ctx.props();
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
onclick={ctx.link().callback(|_| Msg::Open)}
|
||||||
|
button_ref={self.show_button_ref.clone()}
|
||||||
|
>
|
||||||
|
{"Show overlay"}
|
||||||
|
</Button>
|
||||||
|
<Overlay
|
||||||
|
open={self.open}
|
||||||
|
onclose={ctx.link().callback(|_| Msg::Close)}
|
||||||
|
{backdrop}
|
||||||
|
class={classes!(
|
||||||
|
DARK.with(|x| x.borrow().then_some("bp3-dark")),
|
||||||
|
self.tall.then_some("docs-overlay-example-tall"),
|
||||||
|
)}
|
||||||
|
style="left: calc(50vw - 200px); margin: 10vh 0; top: 0; width: 400px;"
|
||||||
|
>
|
||||||
|
<Card elevation={Elevation::Level4} style="height: 100%">
|
||||||
|
<H3>{"I'm an Overlay!"}</H3>
|
||||||
|
<p>{"This is a simple container with some inline styles to position \
|
||||||
|
it on the screen."}</p>
|
||||||
|
<p>{"Click the \"Make me scroll\" button below to make this overlay's \
|
||||||
|
content really tall, which will make the overlay's container \
|
||||||
|
(but not the page) scrollable"}</p>
|
||||||
|
<div class="bp3-dialog-footer-actions">
|
||||||
|
<Button
|
||||||
|
intent={Intent::Danger}
|
||||||
|
onclick={ctx.link().callback(|_| Msg::Close)}
|
||||||
|
>
|
||||||
|
{"Close"}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
active={self.tall}
|
||||||
|
onclick={ctx.link().callback(|_| Msg::ToggleTall)}
|
||||||
|
icon={Icon::DoubleChevronDown}
|
||||||
|
right_icon={Icon::DoubleChevronDown}
|
||||||
|
>
|
||||||
|
{"Make me scroll"}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Overlay>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
yewprint-doc/src/overlay/mod.rs
Normal file
79
yewprint-doc/src/overlay/mod.rs
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
mod example;
|
||||||
|
|
||||||
|
use crate::ExampleContainer;
|
||||||
|
use example::*;
|
||||||
|
use yew::prelude::*;
|
||||||
|
use yewprint::{Switch, H1, H5};
|
||||||
|
|
||||||
|
pub struct OverlayDoc {
|
||||||
|
callback: Callback<ExampleProps>,
|
||||||
|
state: ExampleProps,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for OverlayDoc {
|
||||||
|
type Message = ExampleProps;
|
||||||
|
type Properties = ();
|
||||||
|
|
||||||
|
fn create(ctx: &Context<Self>) -> Self {
|
||||||
|
OverlayDoc {
|
||||||
|
callback: ctx.link().callback(|x| x),
|
||||||
|
state: ExampleProps { backdrop: true },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||||
|
self.state = msg;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn view(&self, _ctx: &Context<Self>) -> Html {
|
||||||
|
let example_props = self.state.clone();
|
||||||
|
let source = crate::include_raw_html!(
|
||||||
|
concat!(env!("OUT_DIR"), "/", file!(), ".html"),
|
||||||
|
"bp3-code-block"
|
||||||
|
);
|
||||||
|
|
||||||
|
let props_component = html! {
|
||||||
|
<OverlayProps
|
||||||
|
callback={self.callback.clone()}
|
||||||
|
example_props={example_props.clone()}
|
||||||
|
/>
|
||||||
|
};
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<H1 class={classes!("docs-title")}>{"Overlay"}</H1>
|
||||||
|
<SourceCodeUrl />
|
||||||
|
<div>
|
||||||
|
<ExampleContainer
|
||||||
|
source={source}
|
||||||
|
props={Some(props_component)}
|
||||||
|
>
|
||||||
|
<Example ..example_props />
|
||||||
|
</ExampleContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::build_example_prop_component! {
|
||||||
|
OverlayProps for ExampleProps =>
|
||||||
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<H5>{"Props"}</H5>
|
||||||
|
<Switch
|
||||||
|
onclick={self.update_props(ctx, |props, _| ExampleProps {
|
||||||
|
backdrop: !props.backdrop,
|
||||||
|
..props
|
||||||
|
})}
|
||||||
|
checked={ctx.props().example_props.backdrop}
|
||||||
|
label={html!("Backdrop")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::build_source_code_component!();
|
|
@ -120,23 +120,27 @@
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.docs-icon-search {
|
.docs-icon-search {
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.docs-icon-list {
|
.docs-icon-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: auto auto auto auto;
|
grid-template-columns: auto auto auto auto;
|
||||||
row-gap: 40px;
|
row-gap: 40px;
|
||||||
column-gap: 20px;
|
column-gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.docs-icon-list-item {
|
.docs-icon-list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 3px;
|
gap: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.docs-overlay-example-tall {
|
||||||
|
height: 200%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue