diff --git a/.idea/leptos-use.iml b/.idea/leptos-use.iml index 60999d5..6ee18d0 100644 --- a/.idea/leptos-use.iml +++ b/.idea/leptos-use.iml @@ -10,8 +10,10 @@ + + diff --git a/docs/book/book.toml b/docs/book/book.toml index 66f210d..6b2c4d9 100644 --- a/docs/book/book.toml +++ b/docs/book/book.toml @@ -7,5 +7,7 @@ title = "Leptos-Use Documentation" [output.html] no-section-label = true +additional-css = ["custom.css"] +additional-js = ["demo-iframe.js"] [preprocessor.cmdrun] \ No newline at end of file diff --git a/docs/book/custom.css b/docs/book/custom.css new file mode 100644 index 0000000..5cab92c --- /dev/null +++ b/docs/book/custom.css @@ -0,0 +1,15 @@ +iframe.demo { + transition: height 0.25s ease-out; +} + +.demo-container { + position: relative; +} + +.demo-container > a.demo-source { + position: absolute; + right: 10px; + top: 5px; + font-size: 80%; + color: rgb(96 165 250); +} \ No newline at end of file diff --git a/docs/book/demo-iframe.js b/docs/book/demo-iframe.js new file mode 100644 index 0000000..465b1a7 --- /dev/null +++ b/docs/book/demo-iframe.js @@ -0,0 +1,19 @@ +const iframes = Array.prototype.slice.apply(document.getElementsByTagName("iframe")); +for (const [i, iframe] of iframes.entries()) { + iframe.style.height = iframe.getBoundingClientRect().height + "px"; + + iframe.addEventListener('load', () => { + const innerBody = window.frames[i].document.body; + innerBody.style.overflow = "hidden"; + + const resize = () => { + if (innerBody.scrollHeight == 0) { + window.setTimeout(resize, 50); + return; + } + iframe.style.height = innerBody.scrollHeight + "px"; + } + + window.setTimeout(resize, 50); + }); +} diff --git a/docs/book/post_build.py b/docs/book/post_build.py new file mode 100644 index 0000000..20889cd --- /dev/null +++ b/docs/book/post_build.py @@ -0,0 +1,28 @@ +import os +import shutil +import subprocess + + +def main(): + src_dir = os.path.join(os.getcwd(), "src") + for dir in os.listdir(src_dir): + category = dir + category_dir = os.path.join(src_dir, dir) + if os.path.isdir(category_dir): + for file in os.listdir(category_dir): + if file.endswith(".md"): + build_and_copy_demo(category, file) + + +def build_and_copy_demo(category, md_name): + name = md_name[:-3] + example_dir = f"../../examples/{name}" + if os.path.exists(example_dir): + p = subprocess.Popen(["trunk", "build"], cwd=example_dir) + p.wait() + shutil.copytree(os.path.join(example_dir, "dist"), os.path.join("book", category, name, "demo"), + dirs_exist_ok=True) + + +if __name__ == '__main__': + main() diff --git a/docs/book/src/extract_doc_comment.py b/docs/book/src/extract_doc_comment.py index a2f831a..7d5ee7e 100644 --- a/docs/book/src/extract_doc_comment.py +++ b/docs/book/src/extract_doc_comment.py @@ -16,10 +16,26 @@ def main(): line = line.replace("```", "```rust,ignore") in_code_block = not in_code_block + line = process_line(line, name) + print(line) elif doc_comment_started: return +def process_line(line, name): + stripped = line.strip() + result = line + + if stripped.startswith("[Link to Demo](https://"): + example_link = stripped.replace("[Link to Demo](", "").replace(")", "") + result = f'''
+ source + +
''' + return result + + if __name__ == '__main__': main() diff --git a/examples/use_throttle_fn/Cargo.toml b/examples/use_throttle_fn/Cargo.toml new file mode 100644 index 0000000..c6f0650 --- /dev/null +++ b/examples/use_throttle_fn/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "use_throttle_fn" +version = "0.1.0" +edition = "2021" + +[dependencies] +leptos = "0.3" +console_error_panic_hook = "0.1" +console_log = "1" +log = "0.4" +leptos-use = { path = "../.." } +web-sys = "0.3" + +[dev-dependencies] +wasm-bindgen = "0.2" +wasm-bindgen-test = "0.3.0" diff --git a/examples/use_throttle_fn/README.md b/examples/use_throttle_fn/README.md new file mode 100644 index 0000000..891a616 --- /dev/null +++ b/examples/use_throttle_fn/README.md @@ -0,0 +1,22 @@ +A simple example for `use_throttle_fn`. + +If you don't have it installed already, install [Trunk](https://trunkrs.dev/) and [Tailwind](https://tailwindcss.com/docs/installation) +as well as the nightly toolchain for Rust and the wasm32-unknown-unknown target: + +```bash +cargo install trunk +npm install -D tailwindcss +rustup toolchain install nightly +rustup target add wasm32-unknown-unknown +``` + +Then, open two terminals. In the first one, run: + +``` +npx tailwindcss -i ./input.css -o ./style/output.css --watch +``` + +In the second one, run: + +```bash +trunk serve --open diff --git a/examples/use_throttle_fn/Trunk.toml b/examples/use_throttle_fn/Trunk.toml new file mode 100644 index 0000000..80e0d61 --- /dev/null +++ b/examples/use_throttle_fn/Trunk.toml @@ -0,0 +1,2 @@ +[build] +public_url = "/utilities/use_throttle_fn/demo/" \ No newline at end of file diff --git a/examples/use_throttle_fn/index.html b/examples/use_throttle_fn/index.html new file mode 100644 index 0000000..ae249a6 --- /dev/null +++ b/examples/use_throttle_fn/index.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/examples/use_throttle_fn/input.css b/examples/use_throttle_fn/input.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/examples/use_throttle_fn/input.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/examples/use_throttle_fn/rust-toolchain.toml b/examples/use_throttle_fn/rust-toolchain.toml new file mode 100644 index 0000000..271800c --- /dev/null +++ b/examples/use_throttle_fn/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" \ No newline at end of file diff --git a/examples/use_throttle_fn/src/main.rs b/examples/use_throttle_fn/src/main.rs new file mode 100644 index 0000000..86f4603 --- /dev/null +++ b/examples/use_throttle_fn/src/main.rs @@ -0,0 +1,39 @@ +use leptos::*; +use leptos_use::use_throttle_fn; + +#[component] +fn Demo(cx: Scope) -> impl IntoView { + let (click_count, set_click_count) = create_signal(cx, 0); + let (throttled_count, set_throttled_count) = create_signal(cx, 0); + + let mut throttled_fn = + use_throttle_fn(move || set_throttled_count(throttled_count() + 1), 1000.0); + + view! { cx, + +

"Delay is set to 1000ms for this demo.."

+

"Button clicked: " { click_count }

+

"Event handler called: " { throttled_count }

+ } +} + +fn main() { + _ = console_log::init_with_level(log::Level::Debug); + console_error_panic_hook::set_once(); + + mount_to_body(|cx| { + view! {cx, +
+ +
+ } + }) +} diff --git a/examples/use_throttle_fn/style/output.css b/examples/use_throttle_fn/style/output.css new file mode 100644 index 0000000..93b4920 --- /dev/null +++ b/examples/use_throttle_fn/style/output.css @@ -0,0 +1,651 @@ +/* +! tailwindcss v3.3.1 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +5. Use the user's configured `sans` font-feature-settings by default. +6. Use the user's configured `sans` font-variation-settings by default. +*/ + +html { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: ui-sans-serif, system-ui, -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"; + /* 4 */ + font-feature-settings: normal; + /* 5 */ + font-variation-settings: normal; + /* 6 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font family by default. +2. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + font-weight: inherit; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ + +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.my-4 { + margin-top: 1rem; + margin-bottom: 1rem; +} + +.my-2 { + margin-top: 0.5rem; + margin-bottom: 0.5rem; +} + +.my-1 { + margin-top: 0.25rem; + margin-bottom: 0.25rem; +} + +.my-3 { + margin-top: 0.75rem; + margin-bottom: 0.75rem; +} + +.block { + display: block; +} + +.rounded { + border-radius: 0.25rem; +} + +.bg-blue-500 { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); +} + +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} + +.bg-gray-500 { + --tw-bg-opacity: 1; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)); +} + +.bg-gray-700 { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); +} + +.bg-blue-600 { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); +} + +.bg-gray-600 { + --tw-bg-opacity: 1; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)); +} + +.p-4 { + padding: 1rem; +} + +.p-5 { + padding: 1.25rem; +} + +.p-6 { + padding: 1.5rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.font-bold { + font-weight: 700; +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.text-gray-100 { + --tw-text-opacity: 1; + color: rgb(243 244 246 / var(--tw-text-opacity)); +} + +.text-gray-200 { + --tw-text-opacity: 1; + color: rgb(229 231 235 / var(--tw-text-opacity)); +} + +.text-gray-300 { + --tw-text-opacity: 1; + color: rgb(209 213 219 / var(--tw-text-opacity)); +} + +.hover\:bg-blue-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)); +} + +.hover\:bg-gray-400:hover { + --tw-bg-opacity: 1; + background-color: rgb(156 163 175 / var(--tw-bg-opacity)); +} + +.hover\:bg-blue-400:hover { + --tw-bg-opacity: 1; + background-color: rgb(96 165 250 / var(--tw-bg-opacity)); +} + +.hover\:bg-blue-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); +} \ No newline at end of file diff --git a/examples/use_throttle_fn/tailwind.config.js b/examples/use_throttle_fn/tailwind.config.js new file mode 100644 index 0000000..599eb9f --- /dev/null +++ b/examples/use_throttle_fn/tailwind.config.js @@ -0,0 +1,10 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: { + files: ["*.html", "./src/**/*.rs"], + }, + theme: { + extend: {}, + }, + plugins: [], +} \ No newline at end of file diff --git a/src/use_throttle_fn.rs b/src/use_throttle_fn.rs index 4125464..8ec7dfd 100644 --- a/src/use_throttle_fn.rs +++ b/src/use_throttle_fn.rs @@ -8,11 +8,11 @@ pub use crate::utils::ThrottleOptions; /// Throttle execution of a function. /// Especially useful for rate limiting execution of handlers on events like resize and scroll. /// -/// > Throttle is a spring that throws balls: after a ball flies out it needs some time to shrink back, so it cannot throw any more balls unless it's ready. +/// > Throttle is a spring that throws balls: After a ball flies out it needs some time to shrink back, so it cannot throw any more balls until it's ready. /// /// ## Demo /// -/// TODO +/// [Link to Demo](https://github.com/synphonyte/leptos-use/tree/main/examples/use_throttle_fn) /// /// ## Usage ///