@viasat/beam-react 2.47.0 → 2.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,206 +1,227 @@
1
- import { jsxs as S, jsx as l } from "react/jsx-runtime";
2
- import De from "clsx";
3
- import { forwardRef as Fe } from "react";
4
- import { s as a, b as he, c as s, a as xe } from "../../../chunks/DateField.Segment.C2qoaY0Z.js";
5
- import { t as ye } from "../../../chunks/constants.Cruz2A1w.js";
6
- import { H as Se } from "../../../chunks/form.context.cEuTL68U.js";
7
- import { LabelProvider as Ie } from "../../Form/contexts/label.context.es.js";
8
- import { HelperTextProvider as we } from "../../Form/contexts/helperText.context.es.js";
9
- import { useUniversalRef as Re } from "../../Form/hooks/useUniversalRef.hook.es.js";
10
- import { DateFieldSegments as Ne, PARTS_ORDER as I } from "./DateField.Segments.es.js";
11
- import { toISODateString as Ve } from "./DateField.utils.es.js";
12
- import { useDateFieldFocus as Be } from "./useDateFieldFocus.es.js";
13
- import { useDateFieldForm as Ce } from "./useDateFieldForm.es.js";
14
- import { useDateFieldKeyboard as Oe } from "./useDateFieldKeyboard.es.js";
15
- import { useDateFieldSegments as Pe } from "./useDateFieldSegments.es.js";
16
- import { useDateFieldValidity as Te } from "./useDateFieldValidity.es.js";
17
- import { useDateFieldValue as Me } from "./useDateFieldValue.es.js";
18
- import { useInvalidState as qe } from "./useInvalidState.es.js";
19
- const aa = Fe(
1
+ import { jsxs as N, jsx as r } from "react/jsx-runtime";
2
+ import xe from "clsx";
3
+ import { forwardRef as Ie, useEffect as Ne } from "react";
4
+ import { s as a, b as we, c as s, a as w } from "../../../chunks/DateField.Segment.BVe6TzWY.js";
5
+ import { t as Re } from "../../../chunks/constants.Cruz2A1w.js";
6
+ import { H as Ve } from "../../../chunks/form.context.cEuTL68U.js";
7
+ import { LabelProvider as Me } from "../../Form/contexts/label.context.es.js";
8
+ import { HelperTextProvider as Oe } from "../../Form/contexts/helperText.context.es.js";
9
+ import { useUniversalRef as Be } from "../../Form/hooks/useUniversalRef.hook.es.js";
10
+ import { DateFieldSegments as Ce, PARTS_ORDER as R } from "./DateField.Segments.es.js";
11
+ import { isMinMaxMisconfigured as Ee, dateKeyOrNull as V, toISODateString as Pe } from "./DateField.utils.es.js";
12
+ import { useDateFieldFocus as Te } from "./useDateFieldFocus.es.js";
13
+ import { useDateFieldForm as qe } from "./useDateFieldForm.es.js";
14
+ import { useDateFieldKeyboard as He } from "./useDateFieldKeyboard.es.js";
15
+ import { useDateFieldSegments as Ke } from "./useDateFieldSegments.es.js";
16
+ import { useDateFieldValidity as Le } from "./useDateFieldValidity.es.js";
17
+ import { useDateFieldValue as $e } from "./useDateFieldValue.es.js";
18
+ import { useInvalidState as je } from "./useInvalidState.es.js";
19
+ const da = Ie(
20
20
  function({
21
- value: w,
22
- defaultValue: R,
23
- onChange: N,
24
- label: t = null,
25
- helperText: o = null,
26
- error: n,
27
- hideRequiredMarker: V = !1,
28
- validationRules: B,
29
- width: C,
30
- theme: m,
31
- fluid: O = !1,
32
- disabled: P = !1,
33
- readOnly: T = !1,
34
- required: M = !1,
35
- name: u,
36
- id: q,
37
- className: L,
38
- style: E,
39
- "aria-label": H,
40
- "aria-describedby": $,
41
- "aria-labelledby": j,
42
- ...K
43
- }, W) {
21
+ value: M,
22
+ defaultValue: O,
23
+ onChange: B,
24
+ minDate: t,
25
+ maxDate: d,
26
+ getClampAnnouncement: C,
27
+ label: n = null,
28
+ helperText: u = null,
29
+ error: m,
30
+ hideRequiredMarker: E = !1,
31
+ validationRules: P,
32
+ width: T,
33
+ theme: c,
34
+ fluid: q = !1,
35
+ disabled: H = !1,
36
+ readOnly: K = !1,
37
+ required: L = !1,
38
+ name: f,
39
+ id: $,
40
+ className: j,
41
+ style: A,
42
+ "aria-label": W,
43
+ "aria-describedby": _,
44
+ "aria-labelledby": U,
45
+ ...k
46
+ }, z) {
44
47
  const {
45
48
  disabled: e,
46
- readOnly: d,
47
- required: f,
48
- invalid: A,
49
- errorMessageProvided: c,
50
- defaultValue: U,
51
- errorId: p,
52
- helperTextId: _,
53
- validationErrorsId: k,
54
- labelId: b,
55
- ariaDescribedBy: z,
56
- ariaLabelledBy: G,
57
- showErrors: J
58
- } = Ce({
59
- name: u,
60
- disabled: P,
61
- readOnly: T,
62
- required: M,
63
- defaultValue: R,
64
- error: n,
65
- hasHelperText: !!o,
66
- hasLabel: !!t,
67
- validationRules: B,
68
- ariaDescribedBy: $,
69
- ariaLabelledBy: j
70
- }), { refFn: Q, ref: g } = Re(W), { segmentRefs: X, registerSegmentRef: Y } = Pe(), {
71
- segmentText: Z,
72
- segmentValues: v,
73
- currentValue: D,
74
- wasTouched: ee,
75
- appendDigit: ae,
76
- adjustSegment: re,
77
- deleteLastDigit: le,
78
- clearSegment: ie,
79
- beginSegmentEdit: se,
80
- commitOnBlur: de
81
- } = Me({
82
- value: w,
83
- defaultValue: U,
84
- onChange: N
49
+ readOnly: o,
50
+ required: p,
51
+ invalid: G,
52
+ errorMessageProvided: b,
53
+ defaultValue: J,
54
+ errorId: g,
55
+ helperTextId: Q,
56
+ validationErrorsId: X,
57
+ labelId: v,
58
+ ariaDescribedBy: Y,
59
+ ariaLabelledBy: Z,
60
+ showErrors: ee
61
+ } = qe({
62
+ name: f,
63
+ disabled: H,
64
+ readOnly: K,
65
+ required: L,
66
+ defaultValue: O,
67
+ error: m,
68
+ hasHelperText: !!u,
69
+ hasLabel: !!n,
70
+ validationRules: P,
71
+ ariaDescribedBy: _,
72
+ ariaLabelledBy: U
73
+ });
74
+ Ne(() => {
75
+ process.env.NODE_ENV !== "production" && Ee(t, d) && console.warn(
76
+ "DateField: `minDate` is after `maxDate` — no date satisfies both, so the blur clamp is disabled and values are left as typed."
77
+ );
78
+ }, [V(t), V(d)]);
79
+ const { refFn: ae, ref: F } = Be(z), { segmentRefs: re, registerSegmentRef: ie } = Ke(), {
80
+ segmentText: le,
81
+ segmentValues: D,
82
+ currentValue: h,
83
+ wasTouched: se,
84
+ appendDigit: te,
85
+ adjustSegment: de,
86
+ clearSegment: oe,
87
+ beginSegmentEdit: ne,
88
+ commitOnBlur: ue,
89
+ clampAnnouncement: me
90
+ } = $e({
91
+ value: M,
92
+ defaultValue: J,
93
+ onChange: B,
94
+ minDate: t,
95
+ maxDate: d,
96
+ getClampAnnouncement: C
85
97
  }), {
86
- focusedSegment: F,
87
- fieldTabIndex: te,
88
- handleSegmentFocus: h,
89
- handleFieldFocus: oe,
90
- handleFieldBlur: ne,
91
- handleFieldMouseDown: me,
98
+ focusedSegment: y,
99
+ fieldTabIndex: ce,
100
+ handleSegmentFocus: S,
101
+ handleFieldFocus: fe,
102
+ handleFieldBlur: pe,
103
+ handleFieldMouseDown: be,
92
104
  focusNext: x,
93
- focusPrevious: ue
94
- } = Be({
105
+ focusPrevious: ge
106
+ } = Te({
95
107
  disabled: e,
96
- fieldRef: g,
97
- segmentRefs: X,
98
- partsOrder: I,
99
- onSegmentFocusChange: se,
100
- onFieldBlur: de
101
- }), fe = Oe({
108
+ fieldRef: F,
109
+ segmentRefs: re,
110
+ partsOrder: R,
111
+ onSegmentFocusChange: ne,
112
+ onFieldBlur: ue
113
+ }), ve = He({
102
114
  disabled: e,
103
- readOnly: d,
104
- fieldRef: g,
115
+ readOnly: o,
116
+ fieldRef: F,
105
117
  focusNext: x,
106
- focusPrevious: ue,
107
- adjustSegment: re,
108
- deleteLastDigit: le,
109
- clearSegment: ie
110
- }), { isInvalid: ce } = Te({
111
- segments: v,
112
- currentValue: D,
113
- wasTouched: ee,
114
- isFocused: F !== null
115
- }), pe = (r, i) => {
116
- const { advanced: ve } = ae(r, i);
117
- ve && x(r);
118
- }, y = qe({
119
- formInvalid: A,
120
- valueInvalid: ce
121
- }), be = (r) => {
118
+ focusPrevious: ge,
119
+ adjustSegment: de,
120
+ clearSegment: oe
121
+ }), { isInvalid: Fe } = Le({
122
+ segments: D,
123
+ currentValue: h,
124
+ wasTouched: se,
125
+ isFocused: y !== null
126
+ }), De = (i, l) => {
127
+ const { advanced: Se } = te(i, l);
128
+ Se && x(i);
129
+ }, I = je({
130
+ formInvalid: G,
131
+ valueInvalid: Fe
132
+ }), he = (i) => {
122
133
  if (e) return;
123
- const i = r.target.closest("label");
124
- !i || i.id !== b || (r.preventDefault(), h(I[0]));
125
- }, ge = De(
126
- a[he],
127
- m && ye(m),
128
- O && a[`${s}fluid`],
129
- y && a[`${s}error`],
134
+ const l = i.target.closest("label");
135
+ !l || l.id !== v || (i.preventDefault(), S(R[0]));
136
+ }, ye = xe(
137
+ a[we],
138
+ c && Re(c),
139
+ q && a[`${s}fluid`],
140
+ I && a[`${s}error`],
130
141
  e && a[`${s}disabled`],
131
- d && a[`${s}read-only`],
132
- L
142
+ o && a[`${s}read-only`],
143
+ j
133
144
  );
134
- return /* @__PURE__ */ S(
145
+ return /* @__PURE__ */ N(
135
146
  "div",
136
147
  {
137
- className: ge,
138
- style: { ...E, maxWidth: C },
139
- onMouseDownCapture: be,
148
+ className: ye,
149
+ style: { ...A, maxWidth: T },
150
+ onMouseDownCapture: he,
140
151
  children: [
141
- /* @__PURE__ */ l(
142
- Ie,
152
+ /* @__PURE__ */ r(
153
+ Me,
143
154
  {
144
- ctxId: b,
155
+ ctxId: v,
145
156
  ctxDisabled: e,
146
- ctxRequired: f && !V,
147
- children: t
157
+ ctxRequired: p && !E,
158
+ children: n
148
159
  }
149
160
  ),
150
- /* @__PURE__ */ l(
161
+ /* @__PURE__ */ r(
151
162
  "div",
152
163
  {
153
- ...K,
154
- ref: Q,
155
- id: q,
164
+ ...k,
165
+ ref: ae,
166
+ id: $,
156
167
  role: "group",
157
- "aria-label": H,
158
- "aria-labelledby": G,
168
+ "aria-label": W,
169
+ "aria-labelledby": Z,
159
170
  "aria-disabled": e || void 0,
160
- "aria-required": f || void 0,
161
- "aria-invalid": y || void 0,
162
- "aria-describedby": z,
163
- "aria-errormessage": c ? p : void 0,
164
- tabIndex: te,
165
- className: a[xe.field],
166
- onMouseDown: me,
167
- onFocus: oe,
168
- children: /* @__PURE__ */ l(
169
- Ne,
171
+ "aria-required": p || void 0,
172
+ "aria-invalid": I || void 0,
173
+ "aria-describedby": Y,
174
+ "aria-errormessage": b ? g : void 0,
175
+ tabIndex: ce,
176
+ className: a[w.field],
177
+ onMouseDown: be,
178
+ onFocus: fe,
179
+ children: /* @__PURE__ */ r(
180
+ Ce,
170
181
  {
171
- segmentText: Z,
172
- segmentValues: v,
173
- focusedSegment: F,
182
+ segmentText: le,
183
+ segmentValues: D,
184
+ focusedSegment: y,
174
185
  disabled: e,
175
- readOnly: d,
176
- onSegmentFocus: h,
177
- onSegmentBlur: ne,
178
- onSegmentInput: pe,
179
- onSegmentKeyDown: fe,
180
- registerSegmentRef: Y
186
+ readOnly: o,
187
+ onSegmentFocus: S,
188
+ onSegmentBlur: pe,
189
+ onSegmentInput: De,
190
+ onSegmentKeyDown: ve,
191
+ registerSegmentRef: ie
181
192
  }
182
193
  )
183
194
  }
184
195
  ),
185
- /* @__PURE__ */ l(
196
+ /* @__PURE__ */ r(
197
+ "span",
198
+ {
199
+ role: "status",
200
+ "aria-live": "polite",
201
+ "aria-atomic": "true",
202
+ className: a[w.srStatus],
203
+ children: me
204
+ }
205
+ ),
206
+ /* @__PURE__ */ r(
186
207
  "input",
187
208
  {
188
209
  type: "hidden",
189
- name: u,
190
- value: Ve(D),
210
+ name: f,
211
+ value: Pe(h),
191
212
  disabled: e
192
213
  }
193
214
  ),
194
- /* @__PURE__ */ S(we, { ctxId: _, ctxDisabled: e, children: [
195
- o,
196
- c && /* @__PURE__ */ l(Se, { id: p, appearance: "negative", children: n })
215
+ /* @__PURE__ */ N(Oe, { ctxId: Q, ctxDisabled: e, children: [
216
+ u,
217
+ b && /* @__PURE__ */ r(Ve, { id: g, appearance: "negative", children: m })
197
218
  ] }),
198
- J(k)
219
+ ee(X)
199
220
  ]
200
221
  }
201
222
  );
202
223
  }
203
224
  );
204
225
  export {
205
- aa as DateField
226
+ da as DateField
206
227
  };
@@ -89,9 +89,21 @@ export interface DateFieldProps extends DateFieldInputAttributes {
89
89
  defaultValue?: Nullable<Date>;
90
90
  /**
91
91
  * Fires when the derived `Date | null` value transitions.
92
- * In DF-1, user-input handlers don't exist yet — wired up in DF-2.
93
92
  */
94
93
  onChange?: (value: Nullable<Date>) => void;
94
+ /**
95
+ * Lower bound; on blur, a touched value springs up to it. Use `validationRules` for validation.
96
+ */
97
+ minDate?: Date;
98
+ /**
99
+ * Upper bound; on blur, a touched value springs down to it. Use `validationRules` for validation.
100
+ */
101
+ maxDate?: Date;
102
+ /**
103
+ * Called when a touched value springs to a bound on blur; return a localized
104
+ * message announced politely to screen readers. Omit → no announcement.
105
+ */
106
+ getClampAnnouncement?: (clampedDate: Date) => string;
95
107
  }
96
108
  /**
97
109
  * Internal props for the segment subcomponent. Not part of the public API.
@@ -103,8 +115,15 @@ export interface DateFieldSegmentProps {
103
115
  /** Numeric segment value — used for `aria-valuenow`. `null` when the segment has no committed value. */
104
116
  value: Nullable<number>;
105
117
  /**
106
- * The upper bound announced as `aria-valuemax`.
107
- * For day: month-aware (e.g. 28 for Feb non-leap); for month: 12; for year: 9999.
118
+ * The lower bound announced as `aria-valuemin` — an intrinsic calendar
119
+ * range, NOT the `minDate` prop (day/month: always 1; year: always 1).
120
+ * Computed by `DateField.Segments` so the segment itself stays a pure renderer.
121
+ */
122
+ valueMin: number;
123
+ /**
124
+ * The upper bound announced as `aria-valuemax` — an intrinsic calendar
125
+ * range, NOT the `maxDate` prop (day: month-aware, e.g. 28 for Feb
126
+ * non-leap; month: 12; year: always 9999).
108
127
  * Computed by `DateField.Segments` so the segment itself stays a pure renderer.
109
128
  */
110
129
  valueMax: number;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./DateField.validation.cjs.js"),s=31,o=12,m={day:s,month:o,year:9999},u=(e,t,n)=>Math.min(n,Math.max(t,e)),g=(e,t)=>((e-1)%t+t)%t+1,S=2024,y=(e,t)=>t==null?31:new Date(e??S,t,0).getDate(),M=()=>{const e=new Date;return{day:e.getDate(),month:e.getMonth()+1,year:e.getFullYear()}},N=(e,t,n,r)=>{if(n==="min")return e==="year"?null:1;if(n==="max")return e==="year"?null:e==="day"?r.daysInMonth:o;if(t==null)return r.today[e];if(e==="year")return u(t+n,1,9999);const a=e==="day"?s:o;return g(t+n,a)},T={day:"",month:"",year:""},c=e=>e instanceof Date&&!Number.isNaN(e.getTime()),d=e=>{const{day:t,month:n,year:r}=e;if(t==null||n==null||r==null)return null;const a=new Date(r,n-1,t);return a.setFullYear(r),Number.isNaN(a.getTime())||a.getFullYear()!==r||a.getMonth()!==n-1||a.getDate()!==t?null:a},f=(e,t)=>e==null&&t==null?!0:e==null||t==null?!1:e.getTime()===t.getTime(),_=e=>{if(!c(e))return"";const t=String(e.getFullYear()).padStart(4,"0"),n=String(e.getMonth()+1).padStart(2,"0"),r=String(e.getDate()).padStart(2,"0");return`${t}-${n}-${r}`},h=e=>e.filter(t=>t.type!=="literal").map(t=>t.type),D=e=>c(e)?{day:String(e.getDate()).padStart(2,"0"),month:String(e.getMonth()+1).padStart(2,"0"),year:String(e.getFullYear()).padStart(4,"0")}:T,l=(e,t)=>{if(t===""||e==="year"&&t.length<i.SEGMENT_MAX_LENGTH.year)return null;const n=parseInt(t,10);return Number.isNaN(n)||n===0?null:n},A=e=>d({day:l("day",e.day),month:l("month",e.month),year:l("year",e.year)}),E=(e,t)=>t===""?"":t.padStart(i.SEGMENT_MAX_LENGTH[e],"0"),p=(e,t,n)=>t===""?{displayValue:n,isPlaceholder:!0}:{displayValue:t.padStart(i.SEGMENT_MAX_LENGTH[e],"0"),isPlaceholder:!1},V=e=>{const t=window.getSelection();if(!t)return;const n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)},F=e=>{var n;if(!e)return;const t=(n=window.getSelection)==null?void 0:n.call(window);t&&t.rangeCount>0&&e.contains(t.anchorNode)&&t.removeAllRanges()};exports.DAY_SPIN_MAX=s;exports.MONTH_MAX=o;exports.SEGMENT_ARIA_MAX=m;exports.adjustSegmentValue=N;exports.clamp=u;exports.clearSelectionWithin=F;exports.deriveValue=d;exports.deriveValueFromText=A;exports.getDaysInMonth=y;exports.getSegmentDisplay=p;exports.getSegmentOrder=h;exports.isSameDateValue=f;exports.normalizeSegmentText=E;exports.segmentNumber=l;exports.segmentTextFromValue=D;exports.selectElementContents=V;exports.toISODateString=_;exports.todayParts=M;exports.wrapInRange=g;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("./DateField.validation.cjs.js"),u=31,s=12,c=1,d=9999,y=(e,t,n)=>Math.min(n,Math.max(t,e)),S=(e,t)=>((e-1)%t+t)%t+1,N=2024,h=(e,t)=>t==null?31:new Date(e??N,t,0).getDate(),T=()=>{const e=new Date;return{day:e.getDate(),month:e.getMonth()+1,year:e.getFullYear()}},l=e=>e instanceof Date&&!Number.isNaN(e.getTime()),_=(e,t,n,r)=>{if(n==="min")return e==="year"?null:1;if(n==="max")return e==="year"?null:e==="day"?r.daysInMonth:s;if(t==null){if(e==="year")return r.today.year;const f=e==="day"?u:s;return n>0?1:f}if(e==="year")return y(t+n,c,d);const o=e==="day"?u:s;return S(t+n,o)},A={day:"",month:"",year:""},M=e=>{const{day:t,month:n,year:r}=e;if(t==null||n==null||r==null)return null;const o=new Date(r,n-1,t);return o.setFullYear(r),Number.isNaN(o.getTime())||o.getFullYear()!==r||o.getMonth()!==n-1||o.getDate()!==t?null:o},E=(e,t)=>e==null&&t==null?!0:e==null||t==null?!1:e.getTime()===t.getTime(),a=e=>e.getFullYear()*1e4+(e.getMonth()+1)*100+e.getDate(),p=e=>l(e)?a(e):null,D=(e,t,n)=>{const r=a(e);return!(l(t)&&r<a(t)||l(n)&&r>a(n))},m=(e,t)=>l(e)&&l(t)&&a(e)>a(t),Y=(e,t,n)=>{if(m(t,n))return e;const r=a(e);return l(t)&&r<a(t)?new Date(t.getFullYear(),t.getMonth(),t.getDate()):l(n)&&r>a(n)?new Date(n.getFullYear(),n.getMonth(),n.getDate()):e},F=e=>{if(!l(e))return"";const t=String(e.getFullYear()).padStart(4,"0"),n=String(e.getMonth()+1).padStart(2,"0"),r=String(e.getDate()).padStart(2,"0");return`${t}-${n}-${r}`},R=e=>e.filter(t=>t.type!=="literal").map(t=>t.type),I=e=>l(e)?{day:String(e.getDate()).padStart(2,"0"),month:String(e.getMonth()+1).padStart(2,"0"),year:String(e.getFullYear()).padStart(4,"0")}:A,i=(e,t)=>{if(t===""||e==="year"&&t.length<g.SEGMENT_MAX_LENGTH.year)return null;const n=parseInt(t,10);return Number.isNaN(n)||n===0?null:n},V=e=>M({day:i("day",e.day),month:i("month",e.month),year:i("year",e.year)}),w=(e,t)=>t===""?"":t.padStart(g.SEGMENT_MAX_LENGTH[e],"0"),X=(e,t,n)=>t===""?{displayValue:n,isPlaceholder:!0}:{displayValue:t.padStart(g.SEGMENT_MAX_LENGTH[e],"0"),isPlaceholder:!1},O=e=>{const t=window.getSelection();if(!t)return;const n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)},P=e=>{var n;if(!e)return;const t=(n=window.getSelection)==null?void 0:n.call(window);t&&t.rangeCount>0&&e.contains(t.anchorNode)&&t.removeAllRanges()};exports.DAY_SPIN_MAX=u;exports.MONTH_MAX=s;exports.YEAR_MAX=d;exports.YEAR_MIN=c;exports.adjustSegmentValue=_;exports.clamp=y;exports.clampDateToRange=Y;exports.clearSelectionWithin=P;exports.dateKeyOrNull=p;exports.deriveValue=M;exports.deriveValueFromText=V;exports.getDaysInMonth=h;exports.getSegmentDisplay=X;exports.getSegmentOrder=R;exports.isDateInRange=D;exports.isMinMaxMisconfigured=m;exports.isSameDateValue=E;exports.normalizeSegmentText=w;exports.segmentNumber=i;exports.segmentTextFromValue=I;exports.selectElementContents=O;exports.toISODateString=F;exports.todayParts=T;exports.wrapInRange=S;
@@ -15,11 +15,12 @@ export declare const DAY_SPIN_MAX = 31;
15
15
  /** Absolute maximum for month (1-based). */
16
16
  export declare const MONTH_MAX = 12;
17
17
  /**
18
- * Announced aria-valuemax per segment type.
19
- * Day uses the absolute calendar max (31); month-aware override for day is
20
- * computed in `DateField.Segments` and passed as `valueMax` to `DateFieldSegment`.
18
+ * Absolute floor/ceiling for the free-spinning year segment. `minDate`/
19
+ * `maxDate` no longer bound the year directly (DF-10: the whole date clamps
20
+ * to those bounds on blur instead — see `commitOnBlur`).
21
21
  */
22
- export declare const SEGMENT_ARIA_MAX: Record<SegmentType, number>;
22
+ export declare const YEAR_MIN = 1;
23
+ export declare const YEAR_MAX = 9999;
23
24
  /** Clamps `n` to `[lo, hi]` (inclusive). */
24
25
  export declare const clamp: (n: number, lo: number, hi: number) => number;
25
26
  /**
@@ -49,7 +50,11 @@ export declare const todayParts: () => {
49
50
  export interface AdjustSegmentContext {
50
51
  /** Days in the current month (use {@link getDaysInMonth} to compute). */
51
52
  daysInMonth: number;
52
- /** Today's local-date values used to seed an empty segment on the first press. */
53
+ /**
54
+ * Today's local-date values. Only `year` is read now — it seeds an empty
55
+ * year segment on the first press. Day/month seed to a fixed first/last
56
+ * valid value instead, so `day`/`month` here go unused.
57
+ */
53
58
  today: {
54
59
  day: number;
55
60
  month: number;
@@ -60,22 +65,15 @@ export interface AdjustSegmentContext {
60
65
  * Computes the next numeric value for a date segment after an increment,
61
66
  * decrement, or boundary jump.
62
67
  *
63
- * Returns `null` to signal "no change" (Home/End on the year segment, which
64
- * has no meaningful bound until DF-10 adds minDate/maxDate).
65
- *
66
- * Rules:
67
- * - **day spin (numeric delta)**: modular wrap within `[1, DAY_SPIN_MAX]` — the
68
- * absolute calendar maximum. Out-of-range dates (e.g. Feb 31) are flagged
69
- * invalid by the existing validity layer (`useDateFieldValidity`), not clamped here.
70
- * - **day End (`'max'`)**: uses `ctx.daysInMonth` — the last valid day of the
71
- * currently selected month (month-aware).
72
- * - **month**: modular wrap within `[1, MONTH_MAX]`.
73
- * - **year**: clamp to `[1, 9999]`; no wrap.
74
- * - **Empty segment + numeric delta**: seeds to `ctx.today[type]` (first press
75
- * sets today's value; subsequent presses step from there).
76
- * - **`'min'`**: returns 1 for day/month, null for year.
77
- * - **`'max'`**: returns `ctx.daysInMonth` for day (End → month-aware last
78
- * valid day), MONTH_MAX for month, null for year.
68
+ * Day and month wrap modularly within their absolute ranges (day:
69
+ * `[1, DAY_SPIN_MAX]`; month: `[1, MONTH_MAX]`); out-of-range dates (e.g. Feb
70
+ * 31) are flagged by the validity layer, not clamped here. Year clamps (no
71
+ * wrap) within `[YEAR_MIN, YEAR_MAX]` and spins free of `minDate`/`maxDate`
72
+ * (DF-10: those clamp the whole date on blur instead — see `commitOnBlur`);
73
+ * year `'min'`/`'max'` (Home/End) are a no-op (`null`). An empty segment seeds
74
+ * on the first numeric press: day/month to a direction-based first/last valid
75
+ * value (positive amount → `1`, negative → `DAY_SPIN_MAX`/`MONTH_MAX`;
76
+ * EPTOOLS-2766), year to `ctx.today.year`.
79
77
  *
80
78
  * @param type - Segment kind (`'day'`, `'month'`, or `'year'`).
81
79
  * @param current - Current numeric value of the segment, or `null` when empty.
@@ -85,6 +83,36 @@ export interface AdjustSegmentContext {
85
83
  export declare const adjustSegmentValue: (type: SegmentType, current: Nullable<number>, amount: SegmentAdjustment, ctx: AdjustSegmentContext) => Nullable<number>;
86
84
  export declare const deriveValue: (segments: SegmentValues) => Nullable<Date>;
87
85
  export declare const isSameDateValue: (a: Nullable<Date>, b: Nullable<Date>) => boolean;
86
+ /**
87
+ * `dateKey` for a possibly-absent/invalid `Date`, collapsing both to `null`
88
+ * (never `NaN` — a `NaN` dependency would itself churn every render). Used to
89
+ * key memo/callback deps on a bound's primitive calendar day instead of the
90
+ * `Date` object's identity.
91
+ */
92
+ export declare const dateKeyOrNull: (d?: Nullable<Date>) => Nullable<number>;
93
+ /**
94
+ * True when `value`'s calendar day falls within `[minDate, maxDate]`
95
+ * (inclusive). Compared by calendar day only, so a `maxDate` with a non-zero
96
+ * time-of-day still accepts the same day. A missing bound is unbounded on
97
+ * that side.
98
+ */
99
+ export declare const isDateInRange: (value: Date, minDate?: Nullable<Date>, maxDate?: Nullable<Date>) => boolean;
100
+ /**
101
+ * True when both bounds are valid Dates but `minDate`'s calendar day is after
102
+ * `maxDate`'s — a misconfiguration where no date can satisfy both. `DateField`
103
+ * dev-warns on this, and `clampDateToRange` skips clamping so a touched value
104
+ * isn't flip-flopped between the two bounds on repeated blurs.
105
+ */
106
+ export declare const isMinMaxMisconfigured: (minDate?: Nullable<Date>, maxDate?: Nullable<Date>) => boolean;
107
+ /**
108
+ * Clamps `value` to the nearest in-range bound by calendar day: `minDate` when
109
+ * the value is before it, `maxDate` when after, else the value unchanged. An
110
+ * invalid/absent bound is ignored (unbounded on that side). Returns a
111
+ * local-midnight `Date` on the bound's calendar day. Used by `commitOnBlur` to
112
+ * normalize a well-formed out-of-range date; structural invalids (Feb 30) never
113
+ * reach here since they derive to `null`.
114
+ */
115
+ export declare const clampDateToRange: (value: Date, minDate?: Nullable<Date>, maxDate?: Nullable<Date>) => Date;
88
116
  export declare const toISODateString: (value: Nullable<Date>) => string;
89
117
  /** Ordered segment types from a parts array (literals stripped). */
90
118
  export declare const getSegmentOrder: (parts: ReadonlyArray<DateFieldPart>) => ReadonlyArray<SegmentType>;