1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! [`DateField`] — segmented date input bound to [`OrbitalDateTime`].
use *;
use DatetimeFormat;
use component_doc;
use use_theme_options;
use cratepicker_style_sheet;
use crate::;
use ;
/// Segmented date input with locale-aware section masks, bound to [`OrbitalDateTime`].
///
/// DateField renders editable month/day/year (or ISO) segments instead of a single text box.
/// Values are stored as start-of-day [`OrbitalDateTime`] in the chosen timezone. Convert at
/// API boundaries via `ToUnixSeconds` or `ToIso8601`. For a text field with popover calendar,
/// use core [`DatePicker`](orbital_core_components::DatePicker) instead.
///
/// # When to use
///
/// - Dense forms that benefit from section-wise date entry
/// - Keyboards-first flows where users tab through date parts
/// - Flows that need segmented date entry without a popover calendar
///
/// # Usage
///
/// 1. Bind `Option<OrbitalDateTime>` via [`DateFieldBind`].
/// 2. Set `appearance.format` to `IsoDate` or `UsDate`.
/// 3. Wrap in [`Field`](orbital_core_components::Field) when a visible label is required.
///
/// # Lifecycle
///
/// - **Value:** each segment commits the parsed date on blur when all required sections are complete.
/// - **Open state:** no popover — segments are always editable inline.
///
/// # Timezone
///
/// `appearance.timezone` controls start-of-day normalization for parsed segment values.
///
/// # Best Practices
///
/// ## Do's
///
/// * Bind with [`OrbitalDateTime`], not raw unix seconds
/// * Wrap preview examples in a native element with `data-testid`
///
/// ## Don'ts
///
/// * Do not use for time-of-day — prefer [`TimeField`](crate::TimeField)
/// * Do not put `data-testid` on the component itself
///
/// # Examples
///
/// ## Segmented input
/// Default US-format month/day/year segments with bind readout for E2E.
/// <!-- preview -->
/// ```rust
/// use orbital_base_components::{OrbitalDateTime, ToUnixSeconds};
/// use crate::preview::{PickerPreviewExample, PickerPreviewKnobs};
/// let value = RwSignal::new(None::<OrbitalDateTime>);
/// view! {
/// <PickerPreviewExample data_testid="date-field-preview">
/// <PickerPreviewKnobs />
/// <DateField bind=value />
/// <div data-testid="date-field-preview-VALUE">{move || value.get().map(|v| v.to_unix_seconds().to_string()).unwrap_or_else(|| "none".to_string())}</div>
/// </PickerPreviewExample>
/// }
/// ```
///
/// ## Bind readout
/// Typing complete segments updates the bound [`OrbitalDateTime`].
/// <!-- preview -->
/// ```rust
/// use orbital_base_components::{OrbitalDateTime, ToUnixSeconds};
/// use crate::preview::PickerPreviewExample;
/// let value = RwSignal::new(None::<OrbitalDateTime>);
/// view! {
/// <PickerPreviewExample data_testid="DF-02">
/// <DateField bind=value />
/// <div data-testid="DF-02-VALUE">{move || value.get().map(|v| v.to_unix_seconds().to_string()).unwrap_or_else(|| "none".to_string())}</div>
/// </PickerPreviewExample>
/// }
/// ```
///
/// ## ISO format
/// Year-month-day segment order for ISO locales.
/// <!-- preview -->
/// ```rust
/// use orbital_base_components::{DatetimeFormat, OrbitalDateTime};
/// use crate::preview::PickerPreviewExample;
/// let value = RwSignal::new(None::<OrbitalDateTime>);
/// view! {
/// <PickerPreviewExample data_testid="DF-03">
/// <DateField bind=value appearance=DateFieldAppearance { format: Signal::from(DatetimeFormat::IsoDate), ..Default::default() } />
/// </PickerPreviewExample>
/// }
/// ```