leptos_motion_dom/
simplified_event_handling.rs

1//! Simplified Event Handling System
2//!
3//! This module provides a simplified, user-friendly event handling API
4//! that removes the complex event system and provides a clean interface.
5
6use crate::*;
7
8/// Drag axis constraint
9#[derive(Clone, Debug, PartialEq)]
10pub enum DragAxis {
11    /// Allow dragging on both X and Y axes
12    Both,
13    /// Allow dragging only on X axis
14    X,
15    /// Allow dragging only on Y axis
16    Y,
17}
18
19/// Drag constraints for limiting drag movement
20#[derive(Clone, Debug, PartialEq, Default)]
21pub struct DragConstraints {
22    /// Left boundary
23    pub left: Option<f64>,
24    /// Right boundary
25    pub right: Option<f64>,
26    /// Top boundary
27    pub top: Option<f64>,
28    /// Bottom boundary
29    pub bottom: Option<f64>,
30}
31
32/// Drag configuration
33#[derive(Clone, Debug)]
34pub struct DragConfig {
35    /// Drag axis constraint
36    pub axis: Option<DragAxis>,
37    /// Drag constraints
38    pub constraints: Option<DragConstraints>,
39    /// Elastic behavior
40    pub elastic: Option<f64>,
41    /// Momentum enabled
42    pub momentum: Option<bool>,
43}
44
45impl Default for DragConfig {
46    fn default() -> Self {
47        Self {
48            axis: Some(DragAxis::Both),
49            constraints: None,
50            elastic: Some(0.0),
51            momentum: Some(false),
52        }
53    }
54}
55
56/// Motion component props
57#[derive(Clone, Debug)]
58pub struct MotionProps {
59    /// Initial animation state
60    pub initial: Option<AnimationTarget>,
61    /// Target animation state
62    pub animate: Option<AnimationTarget>,
63    /// Exit animation state
64    pub exit: Option<AnimationTarget>,
65    /// Transition configuration
66    pub transition: Option<Transition>,
67    /// Animation variants
68    pub variants: Option<Variants>,
69    /// Layout animation enabled
70    pub layout: Option<bool>,
71    /// Drag configuration
72    pub drag: Option<DragConfig>,
73    /// Hover animation state
74    pub while_hover: Option<AnimationTarget>,
75    /// Tap animation state
76    pub while_tap: Option<AnimationTarget>,
77    /// Focus animation state
78    pub while_focus: Option<AnimationTarget>,
79    /// In-view animation state
80    pub while_in_view: Option<AnimationTarget>,
81    /// Event handlers
82    pub event_handlers: Option<EventHandlers>,
83}
84
85/// Event handlers for motion components
86#[derive(Clone, Debug)]
87pub struct EventHandlers {
88    /// Click handler
89    pub on_click: Option<fn()>,
90    /// Hover handler
91    pub on_hover: Option<fn()>,
92    /// Focus handler
93    pub on_focus: Option<fn()>,
94}
95
96/// Simplified motion props that removes complex event handling
97///
98/// This is the main public API for motion component props. It provides
99/// a clean, simple interface while hiding the complexity of the
100/// underlying event system.
101#[derive(Clone, Debug, Default)]
102pub struct SimplifiedMotionProps {
103    /// Initial animation state
104    pub initial: Option<AnimationTarget>,
105    /// Target animation state
106    pub animate: Option<AnimationTarget>,
107    /// Exit animation state
108    pub exit: Option<AnimationTarget>,
109    /// Transition configuration
110    pub transition: Option<Transition>,
111    /// Animation variants
112    pub variants: Option<Variants>,
113    /// Layout animation enabled
114    pub layout: Option<bool>,
115    /// Drag configuration
116    pub drag: Option<SimplifiedDragConfig>,
117    /// Hover animation state
118    pub while_hover: Option<AnimationTarget>,
119    /// Tap animation state
120    pub while_tap: Option<AnimationTarget>,
121    /// Focus animation state
122    pub while_focus: Option<AnimationTarget>,
123    /// In-view animation state
124    pub while_in_view: Option<AnimationTarget>,
125
126    // Accessibility fields
127    /// ARIA label
128    pub aria_label: Option<String>,
129    /// ARIA described by
130    pub aria_described_by: Option<String>,
131    /// ARIA expanded state
132    pub aria_expanded: Option<bool>,
133    /// ARIA hidden state
134    pub aria_hidden: Option<bool>,
135    /// Tab index for keyboard navigation
136    pub tab_index: Option<i32>,
137    /// Keyboard accessible
138    pub keyboard_accessible: Option<bool>,
139    /// Respect reduced motion preferences
140    pub respect_reduced_motion: Option<bool>,
141    /// Reduced motion alternative
142    pub reduced_motion_alternative: Option<String>,
143    /// High contrast support
144    pub high_contrast_support: Option<bool>,
145    /// High contrast alternative
146    pub high_contrast_alternative: Option<String>,
147    /// Screen reader announcements
148    pub screen_reader_announcements: Option<bool>,
149    /// Announcement text
150    pub announcement_text: Option<String>,
151    /// Announcement priority
152    pub announcement_priority: Option<String>,
153    /// Focus management
154    pub focus_management: Option<bool>,
155    /// Focus trap
156    pub focus_trap: Option<bool>,
157    /// Focus restore
158    pub focus_restore: Option<bool>,
159    /// Color contrast ratio
160    pub color_contrast_ratio: Option<f64>,
161    /// Color contrast AA compliant
162    pub color_contrast_aa_compliant: Option<bool>,
163    /// Color contrast AAA compliant
164    pub color_contrast_aaa_compliant: Option<bool>,
165    /// Text scaling support
166    pub text_scaling_support: Option<bool>,
167    /// Minimum text size
168    pub min_text_size: Option<f64>,
169    /// Maximum text size
170    pub max_text_size: Option<f64>,
171    /// Minimum touch target size
172    pub min_touch_target_size: Option<f64>,
173    /// Touch target spacing
174    pub touch_target_spacing: Option<f64>,
175    /// Touch target accessible
176    pub touch_target_accessible: Option<bool>,
177    /// Error announcement
178    pub error_announcement: Option<bool>,
179    /// Error recovery
180    pub error_recovery: Option<bool>,
181    /// Error fallback
182    pub error_fallback: Option<String>,
183    /// Maximum animation duration
184    pub max_animation_duration: Option<f64>,
185    /// Animation timing control
186    pub animation_timing_control: Option<bool>,
187    /// Animation pause support
188    pub animation_pause_support: Option<bool>,
189    /// Semantic role
190    pub semantic_role: Option<String>,
191    /// Semantic level
192    pub semantic_level: Option<i32>,
193    /// Semantic landmark
194    pub semantic_landmark: Option<String>,
195    /// RTL support
196    pub rtl_support: Option<bool>,
197    /// Locale aware
198    pub locale_aware: Option<bool>,
199    /// Text direction
200    pub text_direction: Option<String>,
201    /// Assistive technology support
202    pub assistive_technology_support: Option<bool>,
203    /// Assistive technology announcements
204    pub assistive_technology_announcements: Option<bool>,
205    /// Assistive technology control
206    pub assistive_technology_control: Option<bool>,
207    /// Accessibility testing enabled
208    pub accessibility_testing_enabled: Option<bool>,
209    /// Accessibility testing automated
210    pub accessibility_testing_automated: Option<bool>,
211    /// Accessibility testing manual
212    pub accessibility_testing_manual: Option<bool>,
213    /// Accessibility documentation
214    pub accessibility_documentation: Option<bool>,
215    /// Accessibility guidelines
216    pub accessibility_guidelines: Option<String>,
217    /// Accessibility compliance level
218    pub accessibility_compliance_level: Option<String>,
219    /// Accessibility validation
220    pub accessibility_validation: Option<bool>,
221    /// Accessibility validation automated
222    pub accessibility_validation_automated: Option<bool>,
223    /// Accessibility validation manual
224    pub accessibility_validation_manual: Option<bool>,
225    /// Accessibility reporting
226    pub accessibility_reporting: Option<bool>,
227    /// Accessibility reporting automated
228    pub accessibility_reporting_automated: Option<bool>,
229    /// Accessibility reporting manual
230    pub accessibility_reporting_manual: Option<bool>,
231    /// Accessibility monitoring
232    pub accessibility_monitoring: Option<bool>,
233    /// Accessibility monitoring automated
234    pub accessibility_monitoring_automated: Option<bool>,
235    /// Accessibility monitoring manual
236    pub accessibility_monitoring_manual: Option<bool>,
237    /// Accessibility feedback
238    pub accessibility_feedback: Option<bool>,
239    /// Accessibility feedback automated
240    pub accessibility_feedback_automated: Option<bool>,
241    /// Accessibility feedback manual
242    pub accessibility_feedback_manual: Option<bool>,
243}
244
245/// Simplified drag configuration
246#[derive(Clone, Debug)]
247pub struct SimplifiedDragConfig {
248    /// Drag axis constraint
249    pub axis: DragAxis,
250    /// Drag constraints
251    pub constraints: Option<DragConstraints>,
252    /// Elastic behavior
253    pub elastic: f64,
254    /// Momentum enabled
255    pub momentum: bool,
256}
257
258impl SimplifiedMotionProps {
259    /// Create new simplified motion props
260    pub fn new() -> Self {
261        Self::default()
262    }
263
264    /// Set initial animation state
265    pub fn initial(mut self, initial: AnimationTarget) -> Self {
266        self.initial = Some(initial);
267        self
268    }
269
270    /// Set target animation state
271    pub fn animate(mut self, animate: AnimationTarget) -> Self {
272        self.animate = Some(animate);
273        self
274    }
275
276    /// Set exit animation state
277    pub fn exit(mut self, exit: AnimationTarget) -> Self {
278        self.exit = Some(exit);
279        self
280    }
281
282    /// Set transition configuration
283    pub fn transition(mut self, transition: Transition) -> Self {
284        self.transition = Some(transition);
285        self
286    }
287
288    /// Set animation variants
289    pub fn variants(mut self, variants: Variants) -> Self {
290        self.variants = Some(variants);
291        self
292    }
293
294    /// Set layout animation
295    pub fn layout(mut self, layout: bool) -> Self {
296        self.layout = Some(layout);
297        self
298    }
299
300    /// Set drag configuration
301    pub fn drag(mut self, drag: SimplifiedDragConfig) -> Self {
302        self.drag = Some(drag);
303        self
304    }
305
306    /// Set hover animation state
307    pub fn while_hover(mut self, while_hover: AnimationTarget) -> Self {
308        self.while_hover = Some(while_hover);
309        self
310    }
311
312    /// Set tap animation state
313    pub fn while_tap(mut self, while_tap: AnimationTarget) -> Self {
314        self.while_tap = Some(while_tap);
315        self
316    }
317
318    /// Set focus animation state
319    pub fn while_focus(mut self, while_focus: AnimationTarget) -> Self {
320        self.while_focus = Some(while_focus);
321        self
322    }
323
324    /// Set in-view animation state
325    pub fn while_in_view(mut self, while_in_view: AnimationTarget) -> Self {
326        self.while_in_view = Some(while_in_view);
327        self
328    }
329
330    // Accessibility fluent API methods
331    /// Set ARIA label
332    pub fn aria_label(mut self, aria_label: &str) -> Self {
333        self.aria_label = Some(aria_label.to_string());
334        self
335    }
336
337    /// Set ARIA described by
338    pub fn aria_described_by(mut self, aria_described_by: &str) -> Self {
339        self.aria_described_by = Some(aria_described_by.to_string());
340        self
341    }
342
343    /// Set ARIA expanded state
344    pub fn aria_expanded(mut self, aria_expanded: bool) -> Self {
345        self.aria_expanded = Some(aria_expanded);
346        self
347    }
348
349    /// Set ARIA hidden state
350    pub fn aria_hidden(mut self, aria_hidden: bool) -> Self {
351        self.aria_hidden = Some(aria_hidden);
352        self
353    }
354
355    /// Set tab index
356    pub fn tab_index(mut self, tab_index: i32) -> Self {
357        self.tab_index = Some(tab_index);
358        self
359    }
360
361    /// Set keyboard accessible
362    pub fn keyboard_accessible(mut self, keyboard_accessible: bool) -> Self {
363        self.keyboard_accessible = Some(keyboard_accessible);
364        self
365    }
366
367    /// Set respect reduced motion
368    pub fn respect_reduced_motion(mut self, respect_reduced_motion: bool) -> Self {
369        self.respect_reduced_motion = Some(respect_reduced_motion);
370        self
371    }
372
373    /// Set reduced motion alternative
374    pub fn reduced_motion_alternative(mut self, reduced_motion_alternative: &str) -> Self {
375        self.reduced_motion_alternative = Some(reduced_motion_alternative.to_string());
376        self
377    }
378
379    /// Set high contrast support
380    pub fn high_contrast_support(mut self, high_contrast_support: bool) -> Self {
381        self.high_contrast_support = Some(high_contrast_support);
382        self
383    }
384
385    /// Set high contrast alternative
386    pub fn high_contrast_alternative(mut self, high_contrast_alternative: &str) -> Self {
387        self.high_contrast_alternative = Some(high_contrast_alternative.to_string());
388        self
389    }
390
391    /// Set screen reader announcements
392    pub fn screen_reader_announcements(mut self, screen_reader_announcements: bool) -> Self {
393        self.screen_reader_announcements = Some(screen_reader_announcements);
394        self
395    }
396
397    /// Set announcement text
398    pub fn announcement_text(mut self, announcement_text: &str) -> Self {
399        self.announcement_text = Some(announcement_text.to_string());
400        self
401    }
402
403    /// Set announcement priority
404    pub fn announcement_priority(mut self, announcement_priority: &str) -> Self {
405        self.announcement_priority = Some(announcement_priority.to_string());
406        self
407    }
408
409    /// Set focus management
410    pub fn focus_management(mut self, focus_management: bool) -> Self {
411        self.focus_management = Some(focus_management);
412        self
413    }
414
415    /// Set focus trap
416    pub fn focus_trap(mut self, focus_trap: bool) -> Self {
417        self.focus_trap = Some(focus_trap);
418        self
419    }
420
421    /// Set focus restore
422    pub fn focus_restore(mut self, focus_restore: bool) -> Self {
423        self.focus_restore = Some(focus_restore);
424        self
425    }
426
427    /// Set color contrast ratio
428    pub fn color_contrast_ratio(mut self, color_contrast_ratio: f64) -> Self {
429        self.color_contrast_ratio = Some(color_contrast_ratio);
430        self
431    }
432
433    /// Set color contrast AA compliant
434    pub fn color_contrast_aa_compliant(mut self, color_contrast_aa_compliant: bool) -> Self {
435        self.color_contrast_aa_compliant = Some(color_contrast_aa_compliant);
436        self
437    }
438
439    /// Set color contrast AAA compliant
440    pub fn color_contrast_aaa_compliant(mut self, color_contrast_aaa_compliant: bool) -> Self {
441        self.color_contrast_aaa_compliant = Some(color_contrast_aaa_compliant);
442        self
443    }
444
445    /// Set text scaling support
446    pub fn text_scaling_support(mut self, text_scaling_support: bool) -> Self {
447        self.text_scaling_support = Some(text_scaling_support);
448        self
449    }
450
451    /// Set minimum text size
452    pub fn min_text_size(mut self, min_text_size: f64) -> Self {
453        self.min_text_size = Some(min_text_size);
454        self
455    }
456
457    /// Set maximum text size
458    pub fn max_text_size(mut self, max_text_size: f64) -> Self {
459        self.max_text_size = Some(max_text_size);
460        self
461    }
462
463    /// Set minimum touch target size
464    pub fn min_touch_target_size(mut self, min_touch_target_size: f64) -> Self {
465        self.min_touch_target_size = Some(min_touch_target_size);
466        self
467    }
468
469    /// Set touch target spacing
470    pub fn touch_target_spacing(mut self, touch_target_spacing: f64) -> Self {
471        self.touch_target_spacing = Some(touch_target_spacing);
472        self
473    }
474
475    /// Set touch target accessible
476    pub fn touch_target_accessible(mut self, touch_target_accessible: bool) -> Self {
477        self.touch_target_accessible = Some(touch_target_accessible);
478        self
479    }
480
481    /// Set error announcement
482    pub fn error_announcement(mut self, error_announcement: bool) -> Self {
483        self.error_announcement = Some(error_announcement);
484        self
485    }
486
487    /// Set error recovery
488    pub fn error_recovery(mut self, error_recovery: bool) -> Self {
489        self.error_recovery = Some(error_recovery);
490        self
491    }
492
493    /// Set error fallback
494    pub fn error_fallback(mut self, error_fallback: &str) -> Self {
495        self.error_fallback = Some(error_fallback.to_string());
496        self
497    }
498
499    /// Set maximum animation duration
500    pub fn max_animation_duration(mut self, max_animation_duration: f64) -> Self {
501        self.max_animation_duration = Some(max_animation_duration);
502        self
503    }
504
505    /// Set animation timing control
506    pub fn animation_timing_control(mut self, animation_timing_control: bool) -> Self {
507        self.animation_timing_control = Some(animation_timing_control);
508        self
509    }
510
511    /// Set animation pause support
512    pub fn animation_pause_support(mut self, animation_pause_support: bool) -> Self {
513        self.animation_pause_support = Some(animation_pause_support);
514        self
515    }
516
517    /// Set semantic role
518    pub fn semantic_role(mut self, semantic_role: &str) -> Self {
519        self.semantic_role = Some(semantic_role.to_string());
520        self
521    }
522
523    /// Set semantic level
524    pub fn semantic_level(mut self, semantic_level: i32) -> Self {
525        self.semantic_level = Some(semantic_level);
526        self
527    }
528
529    /// Set semantic landmark
530    pub fn semantic_landmark(mut self, semantic_landmark: &str) -> Self {
531        self.semantic_landmark = Some(semantic_landmark.to_string());
532        self
533    }
534
535    /// Set RTL support
536    pub fn rtl_support(mut self, rtl_support: bool) -> Self {
537        self.rtl_support = Some(rtl_support);
538        self
539    }
540
541    /// Set locale aware
542    pub fn locale_aware(mut self, locale_aware: bool) -> Self {
543        self.locale_aware = Some(locale_aware);
544        self
545    }
546
547    /// Set text direction
548    pub fn text_direction(mut self, text_direction: &str) -> Self {
549        self.text_direction = Some(text_direction.to_string());
550        self
551    }
552
553    /// Set assistive technology support
554    pub fn assistive_technology_support(mut self, assistive_technology_support: bool) -> Self {
555        self.assistive_technology_support = Some(assistive_technology_support);
556        self
557    }
558
559    /// Set assistive technology announcements
560    pub fn assistive_technology_announcements(
561        mut self,
562        assistive_technology_announcements: bool,
563    ) -> Self {
564        self.assistive_technology_announcements = Some(assistive_technology_announcements);
565        self
566    }
567
568    /// Set assistive technology control
569    pub fn assistive_technology_control(mut self, assistive_technology_control: bool) -> Self {
570        self.assistive_technology_control = Some(assistive_technology_control);
571        self
572    }
573
574    /// Set accessibility testing enabled
575    pub fn accessibility_testing_enabled(mut self, accessibility_testing_enabled: bool) -> Self {
576        self.accessibility_testing_enabled = Some(accessibility_testing_enabled);
577        self
578    }
579
580    /// Set accessibility testing automated
581    pub fn accessibility_testing_automated(
582        mut self,
583        accessibility_testing_automated: bool,
584    ) -> Self {
585        self.accessibility_testing_automated = Some(accessibility_testing_automated);
586        self
587    }
588
589    /// Set accessibility testing manual
590    pub fn accessibility_testing_manual(mut self, accessibility_testing_manual: bool) -> Self {
591        self.accessibility_testing_manual = Some(accessibility_testing_manual);
592        self
593    }
594
595    /// Set accessibility documentation
596    pub fn accessibility_documentation(mut self, accessibility_documentation: bool) -> Self {
597        self.accessibility_documentation = Some(accessibility_documentation);
598        self
599    }
600
601    /// Set accessibility guidelines
602    pub fn accessibility_guidelines(mut self, accessibility_guidelines: &str) -> Self {
603        self.accessibility_guidelines = Some(accessibility_guidelines.to_string());
604        self
605    }
606
607    /// Set accessibility compliance level
608    pub fn accessibility_compliance_level(mut self, accessibility_compliance_level: &str) -> Self {
609        self.accessibility_compliance_level = Some(accessibility_compliance_level.to_string());
610        self
611    }
612
613    /// Set accessibility validation
614    pub fn accessibility_validation(mut self, accessibility_validation: bool) -> Self {
615        self.accessibility_validation = Some(accessibility_validation);
616        self
617    }
618
619    /// Set accessibility validation automated
620    pub fn accessibility_validation_automated(
621        mut self,
622        accessibility_validation_automated: bool,
623    ) -> Self {
624        self.accessibility_validation_automated = Some(accessibility_validation_automated);
625        self
626    }
627
628    /// Set accessibility validation manual
629    pub fn accessibility_validation_manual(
630        mut self,
631        accessibility_validation_manual: bool,
632    ) -> Self {
633        self.accessibility_validation_manual = Some(accessibility_validation_manual);
634        self
635    }
636
637    /// Set accessibility reporting
638    pub fn accessibility_reporting(mut self, accessibility_reporting: bool) -> Self {
639        self.accessibility_reporting = Some(accessibility_reporting);
640        self
641    }
642
643    /// Set accessibility reporting automated
644    pub fn accessibility_reporting_automated(
645        mut self,
646        accessibility_reporting_automated: bool,
647    ) -> Self {
648        self.accessibility_reporting_automated = Some(accessibility_reporting_automated);
649        self
650    }
651
652    /// Set accessibility reporting manual
653    pub fn accessibility_reporting_manual(mut self, accessibility_reporting_manual: bool) -> Self {
654        self.accessibility_reporting_manual = Some(accessibility_reporting_manual);
655        self
656    }
657
658    /// Set accessibility monitoring
659    pub fn accessibility_monitoring(mut self, accessibility_monitoring: bool) -> Self {
660        self.accessibility_monitoring = Some(accessibility_monitoring);
661        self
662    }
663
664    /// Set accessibility monitoring automated
665    pub fn accessibility_monitoring_automated(
666        mut self,
667        accessibility_monitoring_automated: bool,
668    ) -> Self {
669        self.accessibility_monitoring_automated = Some(accessibility_monitoring_automated);
670        self
671    }
672
673    /// Set accessibility monitoring manual
674    pub fn accessibility_monitoring_manual(
675        mut self,
676        accessibility_monitoring_manual: bool,
677    ) -> Self {
678        self.accessibility_monitoring_manual = Some(accessibility_monitoring_manual);
679        self
680    }
681
682    /// Set accessibility feedback
683    pub fn accessibility_feedback(mut self, accessibility_feedback: bool) -> Self {
684        self.accessibility_feedback = Some(accessibility_feedback);
685        self
686    }
687
688    /// Set accessibility feedback automated
689    pub fn accessibility_feedback_automated(
690        mut self,
691        accessibility_feedback_automated: bool,
692    ) -> Self {
693        self.accessibility_feedback_automated = Some(accessibility_feedback_automated);
694        self
695    }
696
697    /// Set accessibility feedback manual
698    pub fn accessibility_feedback_manual(mut self, accessibility_feedback_manual: bool) -> Self {
699        self.accessibility_feedback_manual = Some(accessibility_feedback_manual);
700        self
701    }
702
703    /// Check if any animation is configured
704    pub fn has_animations(&self) -> bool {
705        self.animate.is_some()
706            || self.while_hover.is_some()
707            || self.while_tap.is_some()
708            || self.while_focus.is_some()
709            || self.while_in_view.is_some()
710    }
711
712    /// Check if drag is configured
713    pub fn has_drag(&self) -> bool {
714        self.drag.is_some()
715    }
716
717    /// Check if layout animation is enabled
718    pub fn has_layout(&self) -> bool {
719        self.layout.unwrap_or(false)
720    }
721
722    /// Get the number of configured animations
723    pub fn animation_count(&self) -> usize {
724        let mut count = 0;
725        if self.animate.is_some() {
726            count += 1;
727        }
728        if self.while_hover.is_some() {
729            count += 1;
730        }
731        if self.while_tap.is_some() {
732            count += 1;
733        }
734        if self.while_focus.is_some() {
735            count += 1;
736        }
737        if self.while_in_view.is_some() {
738            count += 1;
739        }
740        count
741    }
742}
743
744impl SimplifiedDragConfig {
745    /// Create new simplified drag config
746    pub fn new() -> Self {
747        Self::default()
748    }
749
750    /// Set drag axis
751    pub fn axis(mut self, axis: DragAxis) -> Self {
752        self.axis = axis;
753        self
754    }
755
756    /// Set drag constraints
757    pub fn constraints(mut self, constraints: DragConstraints) -> Self {
758        self.constraints = Some(constraints);
759        self
760    }
761
762    /// Set elastic behavior
763    pub fn elastic(mut self, elastic: f64) -> Self {
764        self.elastic = elastic;
765        self
766    }
767
768    /// Set momentum enabled
769    pub fn momentum(mut self, momentum: bool) -> Self {
770        self.momentum = momentum;
771        self
772    }
773
774    /// Check if constraints are configured
775    pub fn has_constraints(&self) -> bool {
776        self.constraints.is_some()
777    }
778
779    /// Check if elastic behavior is enabled
780    pub fn has_elastic(&self) -> bool {
781        self.elastic > 0.0
782    }
783}
784
785impl Default for SimplifiedDragConfig {
786    fn default() -> Self {
787        Self {
788            axis: DragAxis::Both,
789            constraints: None,
790            elastic: 0.0,
791            momentum: false,
792        }
793    }
794}
795
796/// Conversion from complex MotionProps to simplified MotionProps
797impl From<MotionProps> for SimplifiedMotionProps {
798    fn from(props: MotionProps) -> Self {
799        Self {
800            initial: props.initial,
801            animate: props.animate,
802            exit: props.exit,
803            transition: props.transition,
804            variants: props.variants,
805            layout: props.layout,
806            drag: props.drag.map(|d| SimplifiedDragConfig {
807                axis: d.axis.unwrap_or(DragAxis::Both),
808                constraints: d.constraints,
809                elastic: d.elastic.unwrap_or(0.0),
810                momentum: d.momentum.unwrap_or(false),
811            }),
812            while_hover: props.while_hover,
813            while_tap: props.while_tap,
814            while_focus: props.while_focus,
815            while_in_view: props.while_in_view,
816
817            // Accessibility fields - all None for now since MotionProps doesn't have them
818            aria_label: None,
819            aria_described_by: None,
820            aria_expanded: None,
821            aria_hidden: None,
822            tab_index: None,
823            keyboard_accessible: None,
824            respect_reduced_motion: None,
825            reduced_motion_alternative: None,
826            high_contrast_support: None,
827            high_contrast_alternative: None,
828            screen_reader_announcements: None,
829            announcement_text: None,
830            announcement_priority: None,
831            focus_management: None,
832            focus_trap: None,
833            focus_restore: None,
834            color_contrast_ratio: None,
835            color_contrast_aa_compliant: None,
836            color_contrast_aaa_compliant: None,
837            text_scaling_support: None,
838            min_text_size: None,
839            max_text_size: None,
840            min_touch_target_size: None,
841            touch_target_spacing: None,
842            touch_target_accessible: None,
843            error_announcement: None,
844            error_recovery: None,
845            error_fallback: None,
846            max_animation_duration: None,
847            animation_timing_control: None,
848            animation_pause_support: None,
849            semantic_role: None,
850            semantic_level: None,
851            semantic_landmark: None,
852            rtl_support: None,
853            locale_aware: None,
854            text_direction: None,
855            assistive_technology_support: None,
856            assistive_technology_announcements: None,
857            assistive_technology_control: None,
858            accessibility_testing_enabled: None,
859            accessibility_testing_automated: None,
860            accessibility_testing_manual: None,
861            accessibility_documentation: None,
862            accessibility_guidelines: None,
863            accessibility_compliance_level: None,
864            accessibility_validation: None,
865            accessibility_validation_automated: None,
866            accessibility_validation_manual: None,
867            accessibility_reporting: None,
868            accessibility_reporting_automated: None,
869            accessibility_reporting_manual: None,
870            accessibility_monitoring: None,
871            accessibility_monitoring_automated: None,
872            accessibility_monitoring_manual: None,
873            accessibility_feedback: None,
874            accessibility_feedback_automated: None,
875            accessibility_feedback_manual: None,
876        }
877    }
878}
879
880/// Conversion from complex DragConfig to simplified DragConfig
881impl From<DragConfig> for SimplifiedDragConfig {
882    fn from(config: DragConfig) -> Self {
883        Self {
884            axis: config.axis.unwrap_or(DragAxis::Both),
885            constraints: config.constraints,
886            elastic: config.elastic.unwrap_or(0.0),
887            momentum: config.momentum.unwrap_or(false),
888        }
889    }
890}
891
892/// Conversion from simplified MotionProps to complex MotionProps
893impl From<SimplifiedMotionProps> for MotionProps {
894    fn from(props: SimplifiedMotionProps) -> Self {
895        Self {
896            initial: props.initial,
897            animate: props.animate,
898            exit: props.exit,
899            transition: props.transition,
900            variants: props.variants,
901            layout: props.layout,
902            drag: props.drag.map(|d| DragConfig {
903                axis: Some(d.axis),
904                constraints: d.constraints,
905                elastic: Some(d.elastic),
906                momentum: Some(d.momentum),
907            }),
908            while_hover: props.while_hover,
909            while_tap: props.while_tap,
910            while_focus: props.while_focus,
911            while_in_view: props.while_in_view,
912            event_handlers: None, // Simplified version doesn't use complex event handlers
913        }
914    }
915}
916
917/// Conversion from simplified DragConfig to complex DragConfig
918impl From<SimplifiedDragConfig> for DragConfig {
919    fn from(config: SimplifiedDragConfig) -> Self {
920        Self {
921            axis: Some(config.axis),
922            constraints: config.constraints,
923            elastic: Some(config.elastic),
924            momentum: Some(config.momentum),
925        }
926    }
927}
928
929#[cfg(test)]
930mod tests {
931    use super::*;
932
933    #[test]
934    fn test_simplified_motion_props_creation() {
935        let props = SimplifiedMotionProps::new();
936        assert!(props.initial.is_none());
937        assert!(props.animate.is_none());
938        assert!(!props.has_animations());
939        assert!(!props.has_drag());
940        assert!(!props.has_layout());
941        assert_eq!(props.animation_count(), 0);
942    }
943
944    #[test]
945    fn test_simplified_motion_props_fluent_api() {
946        let target = std::collections::HashMap::new();
947        let props = SimplifiedMotionProps::new()
948            .animate(target.clone())
949            .layout(true);
950
951        assert!(props.animate.is_some());
952        assert!(props.has_animations());
953        assert!(props.has_layout());
954        assert_eq!(props.animation_count(), 1);
955    }
956
957    #[test]
958    fn test_simplified_drag_config_creation() {
959        let drag_config = SimplifiedDragConfig::new();
960        assert_eq!(drag_config.axis, DragAxis::Both);
961        assert!(!drag_config.has_constraints());
962        assert!(!drag_config.has_elastic());
963    }
964
965    #[test]
966    fn test_simplified_drag_config_fluent_api() {
967        let drag_config = SimplifiedDragConfig::new()
968            .axis(DragAxis::X)
969            .elastic(0.3)
970            .momentum(true);
971
972        assert_eq!(drag_config.axis, DragAxis::X);
973        assert!(drag_config.has_elastic());
974        assert!(drag_config.momentum);
975    }
976
977    #[test]
978    fn test_conversion_from_complex_motion_props() {
979        let complex_props = MotionProps {
980            initial: None,
981            animate: None,
982            exit: None,
983            transition: None,
984            variants: None,
985            layout: Some(true),
986            drag: Some(DragConfig {
987                axis: Some(DragAxis::X),
988                constraints: None,
989                elastic: Some(0.2),
990                momentum: Some(true),
991            }),
992            while_hover: None,
993            while_tap: None,
994            while_focus: None,
995            while_in_view: None,
996            event_handlers: None,
997        };
998
999        let simplified_props = SimplifiedMotionProps::from(complex_props);
1000        assert!(simplified_props.has_layout());
1001        assert!(simplified_props.has_drag());
1002
1003        let drag = simplified_props.drag.unwrap();
1004        assert_eq!(drag.axis, DragAxis::X);
1005        assert_eq!(drag.elastic, 0.2);
1006        assert!(drag.momentum);
1007    }
1008
1009    #[test]
1010    fn test_conversion_to_complex_motion_props() {
1011        let simplified_props = SimplifiedMotionProps::new()
1012            .layout(true)
1013            .drag(SimplifiedDragConfig::new().axis(DragAxis::Y));
1014
1015        let complex_props = MotionProps::from(simplified_props);
1016        assert!(complex_props.layout.unwrap());
1017        assert!(complex_props.drag.is_some());
1018        assert!(complex_props.event_handlers.is_none()); // Simplified version doesn't use complex event handlers
1019    }
1020}