app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit ead3ccc62a182b566252506552269555be31814a
parent d829181a5d3bfaaa16983eabe72097d2533f8255
Author: triesap <tyson@radroots.org>
Date:   Tue, 27 Jan 2026 14:31:20 +0000

ui: migrate dialog attributes to ui-primitives

- add ui-primitives-leptos dependency and re-exports

- drive dialog trigger/content attributes via builders

- attach dialog attributes through use_primitive node refs

- update workspace lockfile for new dependency graph

Diffstat:
MCargo.lock | 11+++++++++++
Mcrates/ui-components/src/dialog.rs | 38+++++++++++++++++++++++++-------------
Mcrates/ui-primitives/Cargo.toml | 1+
Mcrates/ui-primitives/src/lib.rs | 14++++++++++++++
4 files changed, 51 insertions(+), 13 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -1761,6 +1761,7 @@ dependencies = [ "radroots-app-ui-core", "send_wrapper", "ui-primitives-core", + "ui-primitives-leptos", "wasm-bindgen", "web-sys", ] @@ -2699,6 +2700,16 @@ name = "ui-primitives-core" version = "0.1.0" [[package]] +name = "ui-primitives-leptos" +version = "0.1.0" +dependencies = [ + "leptos", + "ui-primitives-core", + "wasm-bindgen", + "web-sys", +] + +[[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/crates/ui-components/src/dialog.rs b/crates/ui-components/src/dialog.rs @@ -5,6 +5,10 @@ use std::sync::{Arc, Mutex}; use radroots_app_ui_core::RadrootsAppUiId; use radroots_app_ui_primitives::{ + dialog_content_attrs, + dialog_trigger_attrs, + use_primitive, + DialogModel, RadrootsAppUiDismissableReason, RadrootsAppUiDismissableLayer, RadrootsAppUiFocusScope, @@ -95,7 +99,13 @@ pub fn RadrootsAppUiDialogTrigger( ) -> impl IntoView { let context = use_context::<RadrootsAppUiDialogContext>() .expect("dialog context"); + let open = context.open; let content_id = context.content_id.clone(); + let attrs = Signal::derive(move || { + let model = DialogModel::new(open.get()); + dialog_trigger_attrs(&model, Some(content_id.as_str())) + }); + let trigger = use_primitive::<html::Button>(attrs, Vec::new()); let on_click = move |_event: MouseEvent| { if disabled { return; @@ -104,16 +114,13 @@ pub fn RadrootsAppUiDialogTrigger( }; view! { <button + node_ref=trigger.node_ref() type="button" id=id class=class style=style disabled=disabled - aria-haspopup="dialog" - aria-expanded=move || if context.open.get() { "true" } else { "false" } - aria-controls=content_id data-ui="dialog-trigger" - data-state=move || radroots_app_ui_dialog_state_value(context.open.get()) on:click=on_click > {children()} @@ -176,11 +183,24 @@ pub fn RadrootsAppUiDialogContent( ) -> impl IntoView { let context = use_context::<RadrootsAppUiDialogContext>() .expect("dialog context"); - let node_ref = NodeRef::<html::Div>::new(); let content_id = context.content_id.clone(); + let open = context.open; + let title_id = context.title_id; + let description_id = context.description_id; let scroll_guard = Arc::new(Mutex::new(None::<RadrootsAppUiScrollLockGuard>)); let modal_guard = Arc::new(Mutex::new(None::<RadrootsAppUiModalGuard>)); let modal = context.modal; + let attrs = Signal::derive(move || { + let mut model = DialogModel::new(open.get()); + model.set_modal(modal); + dialog_content_attrs( + &model, + title_id.get().as_deref(), + description_id.get().as_deref(), + ) + }); + let primitive = use_primitive::<html::Div>(attrs, Vec::new()); + let node_ref = primitive.node_ref(); #[cfg(target_arch = "wasm32")] { @@ -224,9 +244,6 @@ pub fn RadrootsAppUiDialogContent( let on_dismiss = context.dismiss.clone(); - let labelled_by = move || context.title_id.get(); - let described_by = move || context.description_id.get(); - let aria_modal = StoredValue::new(if modal { Some("true".to_string()) } else { None }); let data_ui = StoredValue::new(data_ui.unwrap_or_else(|| "dialog".to_string())); let id_value = StoredValue::new(id.unwrap_or_else(|| content_id.clone())); let class_value = StoredValue::new(class); @@ -244,12 +261,7 @@ pub fn RadrootsAppUiDialogContent( id=move || id_value.get_value() class=move || class_value.get_value() style=move || style_value.get_value() - role="dialog" - aria-modal=move || aria_modal.get_value() - aria-labelledby=labelled_by - aria-describedby=described_by data-ui=move || data_ui.get_value() - data-state=move || radroots_app_ui_dialog_state_value(context.open.get()) > {(children.get_value())()} </div> diff --git a/crates/ui-primitives/Cargo.toml b/crates/ui-primitives/Cargo.toml @@ -13,6 +13,7 @@ crate-type = ["rlib"] radroots-app-ui-core = { path = "../ui-core" } leptos = { workspace = true, features = ["csr"] } ui-primitives-core = { path = "../../refs/ui-primitives/crates/ui-primitives-core" } +ui-primitives-leptos = { path = "../../refs/ui-primitives/crates/ui-primitives-leptos" } [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = { workspace = true } diff --git a/crates/ui-primitives/src/lib.rs b/crates/ui-primitives/src/lib.rs @@ -46,3 +46,17 @@ pub use aria_hidden::{ RadrootsAppUiModalResult, RadrootsAppUiModalTarget, }; +pub use ui_primitives_core::dialog::DialogModel; +pub use ui_primitives_leptos::builders::{ + dialog_content_attrs, + dialog_trigger_attrs, +}; +pub use ui_primitives_leptos::{ + use_primitive, + PrimitiveAttribute, + PrimitiveAttributeValue, + PrimitiveElement, + PrimitiveError, + PrimitiveEvent, + PrimitiveResult, +};