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