Skip to main content

hyle_dioxus/
types.rs

1use std::rc::Rc;
2use std::collections::HashMap;
3
4use dioxus::prelude::Callback;
5use dioxus::prelude::Element;
6use dioxus_signals::{Memo, ReadSignal, Signal};
7use indexmap::IndexMap;
8
9use hyle::{Blueprint, Field, FieldType, MutateInput, Outcome, Primitive, Query, Source, Value};
10use crate::adapter::{HyleDataState, FieldChange};
11/// Internal model name used by `use_forma` for its synthetic query.
12pub(crate) const FORMA_MODEL: &str = "forma";
13// ── Dioxus-specific HyleFilterField ──────────────────────────────────────────
14
15/// Dioxus specialisation of `HyleFilterField` — the `render` field
16/// carries an optional per-field Dioxus render closure.
17pub type HyleFilterField = crate::adapter::HyleFilterField<Rc<dyn Fn(HyleFilterFieldProps) -> Element>>;
18
19/// A single per-field Dioxus transform function.
20pub type DioxusFieldChangeFn = Rc<dyn Fn(&Field) -> Option<FieldChange<Rc<dyn Fn(HyleFilterFieldProps) -> Element>>>>;
21
22/// A map of per-field Dioxus transform functions (keyed by field name).
23pub type DioxusFieldChangeMap = HashMap<String, DioxusFieldChangeFn>;
24
25// ── Dioxus-specific filter/form options ───────────────────────────────────────
26
27/// Options for [`use_filters`](crate::use_filters).
28#[derive(Default)]
29pub struct UseFiltersOptions {
30    pub initial_committed: IndexMap<String, String>,
31    /// Per-field transform map with Dioxus render override support.
32    pub change: Option<DioxusFieldChangeMap>,
33}
34
35/// Options for [`use_form`](crate::use_form).
36#[derive(Default)]
37pub struct UseFormOptions {
38    pub initial_committed: IndexMap<String, String>,
39    /// Per-field transform map with Dioxus render override support.
40    pub change: Option<DioxusFieldChangeMap>,
41}
42
43impl UseFormOptions {
44    /// Add a plain field transform (no render override).
45    ///
46    /// The closure receives the current [`Field`] and returns
47    /// `Some(FieldChange { .. })` to override label / metadata, or `None` to
48    /// leave it unchanged.  Use [`FieldChange::label`] for the common case.
49    pub fn with_change(
50        mut self,
51        key: &str,
52        f: impl Fn(&Field) -> Option<FieldChange> + 'static,
53    ) -> Self {
54        self.change
55            .get_or_insert_with(HashMap::new)
56            .insert(
57                key.to_owned(),
58                Rc::new(move |field: &Field| {
59                    f(field).map(|fc| FieldChange {
60                        field: fc.field,
61                        render: None,
62                    })
63                }),
64            );
65        self
66    }
67}
68
69// ── Source adapter ────────────────────────────────────────────────────────────
70
71/// The result of a source adapter call.
72#[derive(Clone, PartialEq)]
73pub enum HyleSourceState {
74    Loading,
75    Ready(Source),
76    Error(String),
77}
78
79/// A reactive source handle — `ReadOnlySignal<HyleSourceState>`.
80pub type UseSource = ReadSignal<HyleSourceState>;
81
82// ── Adapter config ────────────────────────────────────────────────────────────
83
84/// Unified adapter stored in Dioxus context.
85///
86/// Provide this at the app root via [`use_adapter_config!`](crate::use_adapter_config).
87#[derive(Clone, Copy, PartialEq)]
88pub struct HyleAdapter {
89    pub source: UseSource,
90    pub create: HyleMutation,
91    pub update: HyleMutation,
92    pub delete: HyleMutation,
93}
94
95// ── List state ────────────────────────────────────────────────────────────────
96
97/// State returned by [`use_list`](crate::use_list).
98#[derive(Clone, Copy, PartialEq)]
99pub struct HyleListState {
100    pub data: Memo<HyleDataState>,
101    pub query: Memo<Query>,
102    pub page: Signal<usize>,
103    pub per_page: Signal<usize>,
104    pub sort_field: Signal<Option<String>>,
105    pub sort_ascending: Signal<bool>,
106}
107
108// ── Filter field props ────────────────────────────────────────────────────────
109
110/// Props passed to a custom render function supplied to [`FilterField`](crate::FilterField).
111#[derive(Clone)]
112pub struct HyleFilterFieldProps {
113    pub key: String,
114    pub label: String,
115    pub field: Field,
116    pub options: Option<Vec<(String, String)>>,
117    pub value: String,
118    pub set: Callback<String>,
119}
120
121// ── Mutation ──────────────────────────────────────────────────────────────────
122
123/// A mutation handle.
124#[derive(Clone, Copy, PartialEq)]
125pub struct HyleMutation {
126    pub mutate: Callback<MutateInput>,
127    pub reset: Callback<()>,
128    pub is_pending: Signal<bool>,
129    pub is_success: Signal<bool>,
130    pub error: Signal<Option<String>>,
131}
132
133// ── Bound mutations ───────────────────────────────────────────────────────────
134
135/// Input for a [`BoundMutation`] — like [`MutateInput`] but without `model`.
136#[derive(Clone, Default)]
137pub struct BoundMutateInput {
138    pub id: Option<Value>,
139    pub data: IndexMap<String, String>,
140}
141
142/// A mutation handle with `model` pre-bound.
143#[derive(Clone, Copy)]
144pub struct BoundMutation {
145    pub mutate: Callback<BoundMutateInput>,
146    pub is_pending: Signal<bool>,
147    pub is_success: Signal<bool>,
148    pub error: Signal<Option<String>>,
149}
150
151/// Create/update/delete handles with `model` pre-bound.
152#[derive(Clone, Copy)]
153pub struct BoundMutations {
154    pub create: BoundMutation,
155    pub update: BoundMutation,
156    pub delete: BoundMutation,
157}
158
159// ── Filters state ─────────────────────────────────────────────────────────────
160
161/// State returned by [`use_filters`](crate::use_filters).
162#[derive(Clone, Copy, PartialEq)]
163pub struct HyleFiltersState {
164    pub query: Memo<Query>,
165    pub fields: Memo<Vec<HyleFilterField>>,
166    pub form_data: Signal<IndexMap<String, String>>,
167    pub set_field: Callback<(String, String)>,
168    pub filter_apply: Callback<()>,
169    pub filter_clear: Callback<()>,
170    pub filter_reset_key: Signal<u32>,
171}
172
173// ── Value components ──────────────────────────────────────────────────────────
174
175/// Props passed to a custom value cell renderer in `HyleComponents`.
176#[derive(Clone)]
177pub struct HyleValueProps {
178    pub key: String,
179    pub field: Field,
180    pub value: Value,
181    pub outcome: Outcome,
182    pub model_name: String,
183    pub blueprint: Blueprint,
184    pub components: Option<HyleComponents>,
185}
186
187/// A map of component overrides for value cells and filter inputs.
188#[derive(Clone, Default)]
189pub struct HyleComponents {
190    pub values: indexmap::IndexMap<String, fn(HyleValueProps) -> Element>,
191    pub filters: indexmap::IndexMap<String, fn(HyleFilterFieldProps) -> Element>,
192}
193
194/// Derive the `HyleComponents` key string from a `FieldType`.
195pub fn field_type_key(field_type: &FieldType) -> &'static str {
196    match field_type {
197        FieldType::Primitive { primitive } => match primitive {
198            Primitive::String => "string",
199            Primitive::Number => "number",
200            Primitive::Boolean => "boolean",
201            Primitive::File => "file",
202        },
203        FieldType::Reference { .. } => "reference",
204        FieldType::Array { .. } => "array",
205        FieldType::Shape { .. } => "shape",
206    }
207}
208
209// ── Form hook state ───────────────────────────────────────────────────────────
210
211/// State returned by [`use_form`](crate::use_form).
212#[derive(Clone, Copy, PartialEq)]
213pub struct HyleFormState {
214    pub filters: HyleFiltersState,
215    pub is_edit: bool,
216    pub is_valid: bool,
217    pub on_submit: Callback<()>,
218    pub mutation: HyleMutation,
219}