@khanacademy/wonder-blocks-date-picker 0.1.2 → 1.0.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @khanacademy/wonder-blocks-date-picker
2
2
 
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 76f6e41: Date picker bugfixes: change dateFormat to string formats only, adjust inline padding, remove default width, fix key handling so Escape will only close date picker overlay and not a parent modal
8
+
9
+ ### Minor Changes
10
+
11
+ - 9fd7228: Adjusts input validation for text-based date formats, improves focus management of next/previous month buttons
12
+
13
+ ## 0.1.3
14
+
15
+ ### Patch Changes
16
+
17
+ - 12e04c3: Update component documentation for the `disabled` props to include details about `aria-disabled` being set internally to keep an element focusable while in a disabled state
18
+ - Updated dependencies [12e04c3]
19
+ - @khanacademy/wonder-blocks-form@7.5.4
20
+ - @khanacademy/wonder-blocks-modal@8.5.15
21
+
3
22
  ## 0.1.2
4
23
 
5
24
  ### Patch Changes
@@ -7,6 +7,9 @@ interface Props {
7
7
  value: string | null | undefined;
8
8
  /**
9
9
  * Whether the input element is disabled.
10
+ *
11
+ * Internally, the `aria-disabled` attribute will be set so that the
12
+ * element remains focusable and will be included in the tab order.
10
13
  */
11
14
  disabled?: boolean;
12
15
  /**
@@ -36,11 +39,11 @@ interface Props {
36
39
  *
37
40
  * NOTE: `value` will be null if an invalid date has been entered.
38
41
  */
39
- onChange?: (value: Date | null | undefined, modifiers: Partial<CustomModifiers>) => unknown;
42
+ onChange?: (value: Date | null | undefined, modifiers: Partial<CustomModifiers>, inputValue?: string) => unknown;
40
43
  /**
41
44
  * Used to format the value as a valid Date.
42
45
  */
43
- dateFormat?: Array<string> | string;
46
+ dateFormat?: string;
44
47
  /**
45
48
  * The locale associated to the current Date.
46
49
  */
@@ -73,7 +76,7 @@ interface Props {
73
76
  * parseDate("2024-12-25", "YYYY-MM-DD", "en-US") // => Date object
74
77
  * parseDate("invalid", "YYYY-MM-DD", "en-US") // => null
75
78
  */
76
- parseDate?: (value: string | Date, format: Array<string> | null | undefined | string | null | undefined, locale?: string | null | undefined) => Date | null | undefined;
79
+ parseDate?: (value: string | Date, format: string | null | undefined, locale?: string | null | undefined) => Date | null | undefined;
77
80
  /**
78
81
  * The placeholder assigned to the date field
79
82
  */
@@ -13,6 +13,11 @@ interface Props {
13
13
  * The reference element used to position the popper.
14
14
  */
15
15
  referenceElement: HTMLElement | null | undefined;
16
+ /**
17
+ * Text direction: when "rtl", the overlay is positioned at the end (e.g. bottom-end)
18
+ * so it aligns with the input in RTL layout. Defaults to "ltr" (bottom-start).
19
+ */
20
+ dir?: "ltr" | "rtl";
16
21
  /**
17
22
  * Styles that will be applied to the children.
18
23
  */
@@ -26,5 +31,5 @@ interface Props {
26
31
  * calendar popup in the current view. This includes using it inside a normal
27
32
  * page or inside a Modal component.
28
33
  */
29
- declare const DatePickerOverlay: ({ children, referenceElement, onClose, style, }: Props) => React.ReactElement | null;
34
+ declare const DatePickerOverlay: ({ children, referenceElement, onClose, dir, style, }: Props) => React.ReactElement | null;
30
35
  export default DatePickerOverlay;
@@ -31,10 +31,10 @@ interface Props {
31
31
  updateDate: (arg1?: Temporal.PlainDate | null | undefined) => any;
32
32
  /**
33
33
  * Used to format the value as a valid Date.
34
- * If not specified, defaults to locale-aware short date format.
34
+ * When nullish (undefined or omitted), defaults to locale-aware short date (same as "L").
35
35
  *
36
36
  * Supported formats:
37
- * - **undefined**: Locale-aware short date (default - uses Intl.DateTimeFormat with full year)
37
+ * - **undefined** (omit or pass undefined): Locale-aware short date (same as "L")
38
38
  * - **"L"**: Locale-aware short date (e.g., "1/20/2026" in en-US, "20.01.2026" in de-DE, "20/01/2026" in bg)
39
39
  * - **"LL"**: Locale-aware long date (e.g., "January 20, 2026" in en-US, "20 de enero de 2026" in es)
40
40
  * - Supports manual text editing using locale-specific month names
@@ -42,9 +42,12 @@ interface Props {
42
42
  * - **"MMMM D, YYYY"**: Text format (e.g., "January 20, 2026") - month name localized but US order
43
43
  * - **"dateStyle:short|medium|long|full"**: Explicit Intl.DateTimeFormat dateStyle values
44
44
  */
45
- dateFormat?: Array<string> | string;
45
+ dateFormat?: string;
46
46
  /**
47
47
  * Whether the DatePicker component is disabled.
48
+ *
49
+ * Internally, the `aria-disabled` attribute will be set so that the
50
+ * element remains focusable and will be included in the tab order.
48
51
  */
49
52
  disabled?: boolean;
50
53
  /**
package/dist/es/index.js CHANGED
@@ -14,14 +14,30 @@ import { Popper } from 'react-popper';
14
14
  import { maybeGetPortalMountedModalHostElement } from '@khanacademy/wonder-blocks-modal';
15
15
  import 'react-day-picker/style.css';
16
16
 
17
- const enUSLocaleCode="en-US";function formatDate(date,format,locale){const localeCode=typeof locale==="string"?locale:locale?.code??enUSLocaleCode;const formatString=Array.isArray(format)?format[0]:format;if(!formatString){return date.toLocaleString(localeCode,{year:"numeric",month:"numeric",day:"numeric"})}if(formatString==="L"){return date.toLocaleString(localeCode,{year:"numeric",month:"numeric",day:"numeric"})}if(formatString==="LL"){return date.toLocaleString(localeCode,{dateStyle:"long"})}if(formatString==="dateStyle:short"||formatString==="dateStyle:medium"||formatString==="dateStyle:long"||formatString==="dateStyle:full"){const style=formatString.split(":")[1];return date.toLocaleString(localeCode,{dateStyle:style})}if(formatString==="YYYY-MM-DD"){return date.toString()}if(formatString==="MMMM D, YYYY"||formatString==="MMM D, YYYY"){try{const monthFormat=formatString==="MMMM D, YYYY"?"long":"short";const monthName=date.toLocaleString(localeCode,{month:monthFormat});return `${monthName} ${date.day}, ${date.year}`}catch(error){return date.toString()}}if(formatString==="MM/DD/YYYY"||formatString==="M/D/YYYY"||formatString==="DD/MM/YYYY"){const shouldPad=formatString.includes("MM")||formatString.includes("DD");const month=shouldPad?String(date.month).padStart(2,"0"):String(date.month);const day=shouldPad?String(date.day).padStart(2,"0"):String(date.day);return `${month}/${day}/${date.year}`}try{const options=getOptionsForFormat(formatString);return date.toLocaleString(localeCode,options)}catch(error){console.warn(`Failed to format date with format "${formatString}" and locale "${localeCode}". Falling back to ISO format.`,error);return date.toString()}}function parseDate(str,format,locale){if(!str||str.trim()===""){return undefined}const formats=Array.isArray(format)?format:[format||"L"];try{return Temporal.PlainDate.from(str)}catch{}for(const fmt of formats){try{const parsed=parseWithFormat(str,fmt,locale);if(parsed){return parsed}}catch{continue}}return undefined}const getModifiersForDay=(day,modifiers)=>{const matchedModifiers=[];for(const[modifierName,matcher]of Object.entries(modifiers)){if(!matcher){continue}if(typeof matcher==="function"){if(matcher(day)){matchedModifiers.push(modifierName);}}else if(matcher instanceof Date){if(day.getFullYear()===matcher.getFullYear()&&day.getMonth()===matcher.getMonth()&&day.getDate()===matcher.getDate()){matchedModifiers.push(modifierName);}}}return matchedModifiers};function temporalDateToJsDate(date){return new Date(date.year,date.month-1,date.day)}function jsDateToTemporalDate(date){return Temporal.PlainDate.from({year:date.getFullYear(),month:date.getMonth()+1,day:date.getDate()})}function parseDateToJsDate(value,format,locale){if(value instanceof Date){return value}const temporalDate=parseDate(value,format,locale||undefined);if(temporalDate){const formatted=formatDate(temporalDate,format,locale||undefined);if(formatted===value){return temporalDateToJsDate(temporalDate)}const normalizedFormatted=formatted.replace(/\b0(\d)\b/g,"$1");const normalizedValue=value.replace(/\b0(\d)\b/g,"$1");if(normalizedFormatted===normalizedValue){return temporalDateToJsDate(temporalDate)}if(value===temporalDate.toString()){return temporalDateToJsDate(temporalDate)}if(format==="LL"){const normalizedFormatted=formatted.replace(/\s+/g," ").trim().toLowerCase();const normalizedValue=value.replace(/\s+/g," ").trim().toLowerCase();if(normalizedFormatted===normalizedValue){return temporalDateToJsDate(temporalDate)}return temporalDateToJsDate(temporalDate)}return undefined}return undefined}function getMonths(locale){const format=new Intl.DateTimeFormat(locale||enUSLocaleCode,{month:"long"});const formatShort=new Intl.DateTimeFormat(locale||enUSLocaleCode,{month:"short"});const months=[];for(let i=0;i<12;i++){const date=new Date(2021,i,15);months.push([format.format(date),formatShort.format(date)]);}return months}function getOptionsForFormat(format){const options={};if(format.includes("YYYY")){options.year="numeric";}else if(format.includes("YY")){options.year="2-digit";}if(format.includes("MMMM")){options.month="long";}else if(format.includes("MMM")){options.month="short";}else if(format.includes("MM")){options.month="2-digit";}else if(format.includes("M")){options.month="numeric";}if(format.includes("DD")){options.day="2-digit";}else if(format.includes("D")){options.day="numeric";}if(format.includes("dddd")){options.weekday="long";}else if(format.includes("ddd")){options.weekday="short";}return options}function parseLocaleAwareDate(str,locale){const localeStr=locale||enUSLocaleCode;const cleaned=str.trim();if(!cleaned){return undefined}try{const formatter=new Intl.DateTimeFormat(localeStr,{dateStyle:"short"});const testDate=new Date(2020,0,15);const parts=formatter.formatToParts(testDate);const pattern=parts.map(p=>({type:p.type,value:p.value}));const separators=pattern.filter(p=>p.type==="literal").map(p=>p.value);const inputParts=cleaned.split(new RegExp(`[${separators.map(s=>`\\${s}`).join("")}]`));if(inputParts.length!==3){throw new Error("Not a numeric date format")}const dateComponents={};let partIndex=0;for(const patternPart of pattern){if(patternPart.type==="literal"){continue}const value=parseInt(inputParts[partIndex],10);if(isNaN(value)){throw new Error("Not a numeric date format")}dateComponents[patternPart.type]=value;partIndex++;}if(!dateComponents.year||!dateComponents.month||!dateComponents.day||dateComponents.month<1||dateComponents.month>12||dateComponents.day<1||dateComponents.day>31||dateComponents.year<1e3||dateComponents.year>9999){throw new Error("Invalid date range")}return Temporal.PlainDate.from({year:dateComponents.year,month:dateComponents.month,day:dateComponents.day})}catch{return parseTextDate(cleaned,localeStr)}}function parseTextDate(str,locale){try{const months=getMonths(locale);const numbers=str.match(/\d+/g);if(!numbers||numbers.length<2){return undefined}let monthIndex=-1;const lowerStr=str.toLowerCase();for(let i=0;i<months.length;i++){const[longName,shortName]=months[i];if(lowerStr.includes(longName.toLowerCase())||lowerStr.includes(shortName.toLowerCase())){monthIndex=i+1;break}}if(monthIndex===-1){return undefined}let day;let year;const num1=parseInt(numbers[0],10);const num2=parseInt(numbers[1],10);if(num1>31){year=num1;day=num2;}else if(num2>31||num2.toString().length===4){day=num1;year=num2;}else {day=num1;year=num2;}if(day<1||day>31||monthIndex<1||monthIndex>12||year<1e3||year>9999){return undefined}return Temporal.PlainDate.from({year,month:monthIndex,day})}catch{return undefined}}function parseWithFormat(str,format,locale){if(!format){return undefined}if(format==="L"||format==="LL"||format.startsWith("dateStyle:")){return parseLocaleAwareDate(str,locale)}if(format==="M/D/YYYY"||format==="M-D-YYYY"||format==="MM/DD/YYYY"||format==="MM-DD-YYYY"){const separator=format.includes("/")?"/":"-";const parts=str.split(separator);if(parts.length===3){const month=parseInt(parts[0],10);const day=parseInt(parts[1],10);const year=parseInt(parts[2],10);if(isNaN(month)||isNaN(day)||isNaN(year)||month<1||month>12||day<1||day>31||year<1e3||year>9999){return undefined}try{return Temporal.PlainDate.from({year,month,day})}catch{return undefined}}}if(format==="MMMM D, YYYY"||format==="MMM D, YYYY"){try{const cleaned=str.trim();const localeStr=locale||enUSLocaleCode;const parts=cleaned.split(",");if(parts.length===2){const[monthDay,yearStr]=parts;const year=parseInt(yearStr.trim(),10);if(year<1e3||year>9999){return undefined}const months=getMonths(localeStr).map(m=>m[0]);const monthDayParts=monthDay.trim().split(" ");if(monthDayParts.length===2){const monthName=monthDayParts[0];const day=parseInt(monthDayParts[1],10);const monthIndex=months.findIndex(m=>m.toLowerCase()===monthName.toLowerCase()||m.slice(0,3).toLowerCase()===monthName.toLowerCase());if(monthIndex>=0&&!isNaN(day)&&!isNaN(year)){return Temporal.PlainDate.from({year,month:monthIndex+1,day})}}}}catch{return undefined}}return undefined}const startOfIsoWeek=date=>{const dayOfWeek=date.dayOfWeek;return date.subtract({days:dayOfWeek-1})};const startOfDay=date=>{const result=new Date(date);result.setHours(0,0,0,0);return result};const endOfDay=date=>{const result=new Date(date);result.setHours(23,59,59,999);return result};const TemporalLocaleUtils={formatDate,parseDate,parseDateToJsDate,startOfIsoWeek,startOfDay,endOfDay,temporalDateToJsDate,jsDateToTemporalDate,getModifiersForDay};
17
+ function useCloseOnOutsideClick({refWrapper,datePickerRef,showOverlay,closeOnSelect,close}){React.useEffect(()=>{const handleClick=e=>{const target=e.target;const thisElement=refWrapper.current;const dayPickerCalendar=datePickerRef.current;const isElement=target instanceof Element;const inThisElement=isElement&&thisElement?.contains(target);const inCalendar=isElement&&dayPickerCalendar?.contains(target);const inPortal=isElement&&target.closest("[data-placement]")!==null;const shouldClose=showOverlay&&closeOnSelect&&thisElement&&!inThisElement&&!inCalendar&&!inPortal;if(shouldClose){close();}};document.addEventListener("mouseup",handleClick);return ()=>{document.removeEventListener("mouseup",handleClick);}},[refWrapper,datePickerRef,showOverlay,closeOnSelect,close]);}
18
18
 
19
- const DatePickerInput=React.forwardRef((props,ref)=>{const{value:propValue,onBlur,onClick,onFocus,onKeyDown,onChange,dateFormat,locale=enUSLocaleCode,modifiers,getModifiersForDay,parseDate,placeholder,testId,resetInvalidValueOnBlur=true,["aria-label"]:ariaLabel,...restProps}=props;const[value,setValue]=React.useState(propValue);const lastPropValueRef=React.useRef(propValue);const keepInvalidTextRef=React.useRef(false);const processModifiers=React.useCallback((date,value)=>{if(!getModifiersForDay||!modifiers){return {}}return getModifiersForDay(date,modifiers).reduce((obj,modifier)=>({...obj,[modifier]:true}),{})},[getModifiersForDay,modifiers]);const updateDate=React.useCallback((date,value)=>{if(onChange){onChange(date,processModifiers(date,value));}},[onChange,processModifiers]);const updateDateAsInvalid=React.useCallback(()=>{if(onChange){onChange(null,{});}},[onChange]);const processDate=React.useCallback(inputValue=>{if(!inputValue||inputValue.trim()===""){return}if(!parseDate){return}const date=parseDate(inputValue,dateFormat,locale);if(!date){return}return date},[parseDate,dateFormat,locale]);const isValid=React.useCallback(()=>{const date=processDate(value);if(!date){return false}const modifiersResult=processModifiers(date,value);if(modifiersResult.disabled){return false}return true},[value,processDate,processModifiers]);React.useEffect(()=>{const propValueChanged=lastPropValueRef.current!==propValue;lastPropValueRef.current=propValue;if(propValueChanged){if(keepInvalidTextRef.current&&(!propValue||propValue.trim()==="")){keepInvalidTextRef.current=false;}else {setValue(propValue);keepInvalidTextRef.current=false;}}},[propValue]);useOnMountEffect(()=>{const skipValidation=dateFormat==="LL"&&propValue;if(!skipValidation&&!isValid()){updateDateAsInvalid();}});const handleFocus=e=>{if(onFocus){onFocus(e);}};const pendingValidationRef=React.useRef(false);const validateInput=React.useCallback(()=>{const date=processDate(value);if(date){const modifiersResult=processModifiers(date,value);if(!modifiersResult.disabled){updateDate(date,value);}else {if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDate(date,value);}else {setValue(propValue);}}}else if(value&&value.trim()!==""){if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDateAsInvalid();}else {setValue(propValue);}}else {setValue(propValue);}},[value,processDate,processModifiers,resetInvalidValueOnBlur,propValue,updateDate,updateDateAsInvalid]);const handleBlur=e=>{const movingToCalendar=e.relatedTarget instanceof HTMLElement&&e.relatedTarget.closest('[data-testid="date-picker-overlay"]')!==null;if(movingToCalendar){pendingValidationRef.current=true;if(onBlur){onBlur(e);}return}validateInput();if(onBlur){onBlur(e);}};const handleChange=newValue=>{setValue(newValue);const date=processDate(newValue);if(date){const modifiersResult=processModifiers(date,newValue);if(!modifiersResult.disabled){updateDate(date,newValue);}else if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDate(date,newValue);}}else if(!resetInvalidValueOnBlur&&newValue&&newValue.trim()!==""){keepInvalidTextRef.current=true;updateDateAsInvalid();}};const innerRef=React.useRef(null);React.useImperativeHandle(ref,()=>{const inputElement=innerRef.current;if(!inputElement){return null}inputElement.validateInput=()=>{if(pendingValidationRef.current){pendingValidationRef.current=false;validateInput();}};return inputElement});return jsxs(View,{style:styles$1.container,onClick:e=>{if(!restProps.disabled&&onClick){onClick(e);}},children:[jsx(TextField,{ref:innerRef,...restProps,onBlur:handleBlur,onFocus:handleFocus,onKeyDown:onKeyDown,onChange:handleChange,disabled:restProps.disabled,placeholder:placeholder,value:value??"",testId:testId,"aria-label":ariaLabel,autoComplete:"off",type:"text",style:styles$1.textField}),jsx(PhosphorIcon,{icon:calendarIcon,color:restProps.disabled?semanticColor.core.foreground.disabled.default:semanticColor.core.foreground.instructive.default,size:"small",style:styles$1.icon})]})});const styles$1=StyleSheet.create({container:{alignItems:"center",flexDirection:"row",justifyContent:"stretch"},icon:{pointerEvents:"none",position:"absolute",insetInlineEnd:sizing.size_080},textField:{width:"100%"}});
19
+ const enUSLocaleCode="en-US";const TEXT_FORMAT_STRINGS=["LL","MMMM D, YYYY","MMM D, YYYY"];function isTextFormatDate(formatString){return formatString!=null&&TEXT_FORMAT_STRINGS.includes(formatString)}function normalizeDateStringForComparison(s){return s.trim().toLowerCase().replace(/\s+/g," ").replace(/[,.\u202f]/g," ").replace(/\s+/g," ").trim()}function formatDate(date,formatString,locale){const localeCode=typeof locale==="string"?locale:locale?.code??enUSLocaleCode;if(!formatString){return date.toLocaleString(localeCode,{year:"numeric",month:"numeric",day:"numeric"})}if(formatString==="L"){return date.toLocaleString(localeCode,{year:"numeric",month:"numeric",day:"numeric"})}if(formatString==="LL"){return date.toLocaleString(localeCode,{dateStyle:"long"})}if(formatString==="dateStyle:short"||formatString==="dateStyle:medium"||formatString==="dateStyle:long"||formatString==="dateStyle:full"){const style=formatString.split(":")[1];return date.toLocaleString(localeCode,{dateStyle:style})}if(formatString==="YYYY-MM-DD"){return date.toString()}if(formatString==="MMMM D, YYYY"||formatString==="MMM D, YYYY"){try{const monthFormat=formatString==="MMMM D, YYYY"?"long":"short";const monthName=date.toLocaleString(localeCode,{month:monthFormat});return `${monthName} ${date.day}, ${date.year}`}catch(error){return date.toString()}}if(formatString==="MM/DD/YYYY"||formatString==="M/D/YYYY"||formatString==="DD/MM/YYYY"){const shouldPad=formatString.includes("MM")||formatString.includes("DD");const month=shouldPad?String(date.month).padStart(2,"0"):String(date.month);const day=shouldPad?String(date.day).padStart(2,"0"):String(date.day);return `${month}/${day}/${date.year}`}try{const options=getOptionsForFormat(formatString);return date.toLocaleString(localeCode,options)}catch(error){console.warn(`Failed to format date with format "${formatString}" and locale "${localeCode}". Falling back to ISO format.`,error);return date.toString()}}function parseDate(str,formatString,locale){if(!str||str.trim()===""){return undefined}try{return Temporal.PlainDate.from(str)}catch{}const format=formatString||"L";try{const parsed=parseWithFormat(str,format,locale);if(parsed){return parsed}}catch{}return undefined}const getModifiersForDay=(day,modifiers)=>{const matchedModifiers=[];for(const[modifierName,matcher]of Object.entries(modifiers)){if(!matcher){continue}if(typeof matcher==="function"){if(matcher(day)){matchedModifiers.push(modifierName);}}else if(matcher instanceof Date){if(day.getFullYear()===matcher.getFullYear()&&day.getMonth()===matcher.getMonth()&&day.getDate()===matcher.getDate()){matchedModifiers.push(modifierName);}}}return matchedModifiers};function temporalDateToJsDate(date){return new Date(date.year,date.month-1,date.day)}function jsDateToTemporalDate(date){return Temporal.PlainDate.from({year:date.getFullYear(),month:date.getMonth()+1,day:date.getDate()})}function parseDateToJsDate(value,formatString,locale){if(value instanceof Date){return value}const temporalDate=parseDate(value,formatString,locale||undefined);if(temporalDate){const formatted=formatDate(temporalDate,formatString,locale||undefined);if(formatted===value){return temporalDateToJsDate(temporalDate)}const normalizedFormatted=formatted.replace(/\b0(\d)\b/g,"$1");const normalizedValue=value.replace(/\b0(\d)\b/g,"$1");if(normalizedFormatted===normalizedValue){return temporalDateToJsDate(temporalDate)}if(value===temporalDate.toString()){return temporalDateToJsDate(temporalDate)}const isTextFormat=isTextFormatDate(formatString);if(isTextFormat){const normalizedFormatted=formatted.replace(/\s+/g," ").trim().toLowerCase();const normalizedValue=value.replace(/\s+/g," ").trim().toLowerCase();if(normalizedFormatted===normalizedValue){return temporalDateToJsDate(temporalDate)}if(normalizedFormatted.startsWith(normalizedValue)||normalizedValue.startsWith(normalizedFormatted)){return temporalDateToJsDate(temporalDate)}return undefined}return undefined}return undefined}function getMonths(locale){const format=new Intl.DateTimeFormat(locale||enUSLocaleCode,{month:"long"});const formatShort=new Intl.DateTimeFormat(locale||enUSLocaleCode,{month:"short"});const months=[];for(let i=0;i<12;i++){const date=new Date(2021,i,15);months.push([format.format(date),formatShort.format(date)]);}return months}function getOptionsForFormat(format){const options={};if(format.includes("YYYY")){options.year="numeric";}else if(format.includes("YY")){options.year="2-digit";}if(format.includes("MMMM")){options.month="long";}else if(format.includes("MMM")){options.month="short";}else if(format.includes("MM")){options.month="2-digit";}else if(format.includes("M")){options.month="numeric";}if(format.includes("DD")){options.day="2-digit";}else if(format.includes("D")){options.day="numeric";}if(format.includes("dddd")){options.weekday="long";}else if(format.includes("ddd")){options.weekday="short";}return options}function parseLocaleAwareDate(str,locale){const localeStr=locale||enUSLocaleCode;const cleaned=str.trim();if(!cleaned){return undefined}try{const formatter=new Intl.DateTimeFormat(localeStr,{dateStyle:"short"});const testDate=new Date(2020,0,15);const parts=formatter.formatToParts(testDate);const pattern=parts.map(p=>({type:p.type,value:p.value}));const separators=pattern.filter(p=>p.type==="literal").map(p=>p.value);const inputParts=cleaned.split(new RegExp(`[${separators.map(s=>`\\${s}`).join("")}]`));if(inputParts.length!==3){throw new Error("Not a numeric date format")}const dateComponents={};let partIndex=0;for(const patternPart of pattern){if(patternPart.type==="literal"){continue}const value=parseInt(inputParts[partIndex],10);if(isNaN(value)){throw new Error("Not a numeric date format")}dateComponents[patternPart.type]=value;partIndex++;}if(!dateComponents.year||!dateComponents.month||!dateComponents.day||dateComponents.month<1||dateComponents.month>12||dateComponents.day<1||dateComponents.day>31||dateComponents.year<1e3||dateComponents.year>9999){throw new Error("Invalid date range")}return Temporal.PlainDate.from({year:dateComponents.year,month:dateComponents.month,day:dateComponents.day})}catch{return parseTextDate(cleaned,localeStr)}}function parseTextDate(str,locale){try{const months=getMonths(locale);const numbers=str.match(/\d+/g)??[];const lowerStr=str.toLowerCase();let monthIndex=-1;for(let i=0;i<months.length;i++){const[longName,shortName]=months[i];if(lowerStr.includes(longName.toLowerCase())||lowerStr.includes(shortName.toLowerCase())){monthIndex=i+1;break}}if(monthIndex===-1){return undefined}const now=Temporal.Now.plainDateISO();if(numbers.length>=2){const n1=numbers[0];const n2=numbers[1];if(n1===undefined||n2===undefined){return undefined}let day;let year;const num1=parseInt(n1,10);const num2=parseInt(n2,10);if(num1>31){year=num1;day=num2;}else if(num2>31||num2.toString().length===4){day=num1;year=num2;}else {day=num1;year=num2;}if(day<1||day>31||year<1e3||year>9999){return undefined}return Temporal.PlainDate.from({year,month:monthIndex,day})}if(numbers.length===1){const n0=numbers[0];if(n0===undefined){return undefined}const n=parseInt(n0,10);const isYear=n>=1e3&&n<=9999;const year=isYear?n:now.year;const day=isYear?1:n>=1&&n<=31?n:1;return Temporal.PlainDate.from({year,month:monthIndex,day})}return Temporal.PlainDate.from({year:now.year,month:monthIndex,day:1})}catch{return undefined}}function parseWithFormat(str,format,locale){if(!format){return undefined}if(format==="L"||format==="LL"||format.startsWith("dateStyle:")){return parseLocaleAwareDate(str,locale)}if(format==="M/D/YYYY"||format==="M-D-YYYY"||format==="MM/DD/YYYY"||format==="MM-DD-YYYY"){const separator=format.includes("/")?"/":"-";const parts=str.split(separator);if(parts.length===3){const month=parseInt(parts[0],10);const day=parseInt(parts[1],10);const year=parseInt(parts[2],10);if(isNaN(month)||isNaN(day)||isNaN(year)||month<1||month>12||day<1||day>31||year<1e3||year>9999){return undefined}try{return Temporal.PlainDate.from({year,month,day})}catch{return undefined}}}if(format==="MMMM D, YYYY"||format==="MMM D, YYYY"){try{const cleaned=str.trim();const localeStr=locale||enUSLocaleCode;const parts=cleaned.split(",");if(parts.length===2){const[monthDay,yearStr]=parts;const year=parseInt(yearStr.trim(),10);if(year<1e3||year>9999){return undefined}const months=getMonths(localeStr).map(m=>m[0]);const monthDayParts=monthDay.trim().split(" ");if(monthDayParts.length===2){const monthName=monthDayParts[0];const day=parseInt(monthDayParts[1],10);const monthIndex=months.findIndex(m=>m.toLowerCase()===monthName.toLowerCase()||m.slice(0,3).toLowerCase()===monthName.toLowerCase());if(monthIndex>=0&&!isNaN(day)&&!isNaN(year)){return Temporal.PlainDate.from({year,month:monthIndex+1,day})}}}return parseTextDate(cleaned,localeStr)}catch{return undefined}}return undefined}const startOfIsoWeek=date=>{const dayOfWeek=date.dayOfWeek;return date.subtract({days:dayOfWeek-1})};const startOfDay=date=>{const result=new Date(date);result.setHours(0,0,0,0);return result};const endOfDay=date=>{const result=new Date(date);result.setHours(23,59,59,999);return result};const TemporalLocaleUtils={formatDate,isTextFormatDate,normalizeDateStringForComparison,parseDate,parseDateToJsDate,startOfIsoWeek,startOfDay,endOfDay,temporalDateToJsDate,jsDateToTemporalDate,getModifiersForDay};
20
+
21
+ function useDatePickerModifiers({selectedDateValue,minDate,maxDate}){return React.useMemo(()=>({selected:selectedDateValue,disabled:date=>{const temporalDate=TemporalLocaleUtils.jsDateToTemporalDate(date);return minDate&&Temporal.PlainDate.compare(temporalDate,minDate)<0||maxDate&&Temporal.PlainDate.compare(temporalDate,maxDate)>0||false}}),[selectedDateValue,minDate,maxDate])}
22
+
23
+ function useDisplayMonth({selectedDate}){const initialMonth=React.useMemo(()=>selectedDate!=null?TemporalLocaleUtils.temporalDateToJsDate(selectedDate):undefined,[selectedDate]);const[displayMonth,setDisplayMonth]=React.useState(initialMonth);const displayMonthRef=React.useRef(undefined);const inputDrivenMonthRef=React.useRef(null);const setDisplayMonthAndRefs=React.useCallback(month=>{if(month!==null){displayMonthRef.current=month;setDisplayMonth(month);}else {if(displayMonthRef.current!=null){setDisplayMonth(displayMonthRef.current);}displayMonthRef.current=undefined;}},[]);return {displayMonth,setDisplayMonth,displayMonthRef,inputDrivenMonthRef,setDisplayMonthAndRefs}}
24
+
25
+ function useEscapeKeyupCapture(){const handledEscapeRef=React.useRef(false);React.useEffect(()=>{const handleKeyup=e=>{if(e.key==="Escape"&&handledEscapeRef.current){e.stopPropagation();handledEscapeRef.current=false;}};window.addEventListener("keyup",handleKeyup,true);return ()=>{window.removeEventListener("keyup",handleKeyup,true);}},[]);const handleEscapeKeyDown=React.useCallback((e,onHandled)=>{e.stopPropagation();handledEscapeRef.current=true;onHandled?.();},[]);return {handleEscapeKeyDown}}
26
+
27
+ function useFormatDateForInput({dateFormat,locale}){const localeCode=locale?.code??"en-US";return React.useCallback(date=>{if(date==null){return ""}return TemporalLocaleUtils.formatDate(date,dateFormat,localeCode)},[dateFormat,localeCode])}
28
+
29
+ function isTextFormatCommitComplete(inputValue,dateFromInput,dateFormat,localeCode){if(typeof inputValue!=="string"||inputValue.trim()===""){return false}const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(dateFromInput);const reparsed=TemporalLocaleUtils.parseDate(inputValue,dateFormat,localeCode??undefined);const sameDate=reparsed!=null&&Temporal.PlainDate.compare(reparsed,wrappedDate)===0;const formatted=TemporalLocaleUtils.formatDate(wrappedDate,dateFormat,localeCode??undefined);if(typeof formatted!=="string"){return false}const inputMatchesDisplay=TemporalLocaleUtils.normalizeDateStringForComparison(formatted)===TemporalLocaleUtils.normalizeDateStringForComparison(inputValue);return sameDate&&inputMatchesDisplay}
30
+
31
+ function useOverlayMonthFromInput({inputDrivenMonthRef,setDisplayMonth,setDisplayMonthAndRefs,setCurrentDate,updateDate,dateFormat,localeCode}){const clearInputDrivenMonth=React.useCallback(()=>{inputDrivenMonthRef.current=null;},[inputDrivenMonthRef]);const handleInputChange=React.useCallback((dateFromInput,modifiers,inputValue)=>{if(!dateFromInput){setCurrentDate(null);updateDate(null);return}const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(dateFromInput);const monthDate=new Date(dateFromInput);setDisplayMonth(monthDate);const isDisabled=typeof modifiers.disabled==="function"?modifiers.disabled(dateFromInput):modifiers.disabled;if(isDisabled){inputDrivenMonthRef.current=monthDate;updateDate(wrappedDate);return}const isTextFormat=TemporalLocaleUtils.isTextFormatDate(dateFormat);if(isTextFormat&&inputValue){const isCompleteDate=isTextFormatCommitComplete(inputValue,dateFromInput,dateFormat,localeCode);if(isCompleteDate){inputDrivenMonthRef.current=null;setDisplayMonthAndRefs(monthDate);setCurrentDate(wrappedDate);updateDate(wrappedDate);}else {inputDrivenMonthRef.current=monthDate;}}else {inputDrivenMonthRef.current=null;setDisplayMonthAndRefs(monthDate);setCurrentDate(wrappedDate);updateDate(wrappedDate);}},[inputDrivenMonthRef,setDisplayMonth,setDisplayMonthAndRefs,setCurrentDate,updateDate,dateFormat,localeCode]);return {handleInputChange,clearInputDrivenMonth}}
32
+
33
+ function useSelectedDateSync({selectedDate,setCurrentDate,setDisplayMonthAndRefs}){const prevSelectedDateRef=React.useRef(null);React.useEffect(()=>{setCurrentDate(selectedDate);const key=selectedDate?.toString()??null;const willUpdateDisplayMonth=key!==prevSelectedDateRef.current;if(willUpdateDisplayMonth){prevSelectedDateRef.current=key;if(selectedDate!=null){const jsDate=TemporalLocaleUtils.temporalDateToJsDate(selectedDate);setDisplayMonthAndRefs(jsDate);}}},[selectedDate,setCurrentDate,setDisplayMonthAndRefs]);}
34
+
35
+ const DatePickerInput=React.forwardRef((props,ref)=>{const{value:propValue,onBlur,onClick,onFocus,onKeyDown,onChange,dateFormat,locale=enUSLocaleCode,modifiers,getModifiersForDay,parseDate,placeholder,testId,resetInvalidValueOnBlur=true,["aria-label"]:ariaLabel,...restProps}=props;const[value,setValue]=React.useState(propValue);const lastPropValueRef=React.useRef(propValue);const keepInvalidTextRef=React.useRef(false);const lastTypedTextFormatValueRef=React.useRef(null);const processModifiers=React.useCallback((date,value)=>{if(!getModifiersForDay||!modifiers){return {}}return getModifiersForDay(date,modifiers).reduce((obj,modifier)=>({...obj,[modifier]:true}),{})},[getModifiersForDay,modifiers]);const updateDate=React.useCallback((date,inputValue)=>{if(onChange){onChange(date,processModifiers(date,inputValue),inputValue||undefined);}},[onChange,processModifiers]);const updateDateAsInvalid=React.useCallback(()=>{if(onChange){onChange(null,{});}},[onChange]);const processDate=React.useCallback(inputValue=>{if(!inputValue||inputValue.trim()===""){return}if(!parseDate){return}const date=parseDate(inputValue,dateFormat,locale);if(!date){return}return date},[parseDate,dateFormat,locale]);const isValid=React.useCallback(()=>{const date=processDate(value);if(!date){return false}const modifiersResult=processModifiers(date,value);if(modifiersResult.disabled){return false}return true},[value,processDate,processModifiers]);const isTextFormat=TemporalLocaleUtils.isTextFormatDate(dateFormat);React.useEffect(()=>{const propValueChanged=lastPropValueRef.current!==propValue;lastPropValueRef.current=propValue;if(propValueChanged){const safeProp=propValue??"";const safeValue=value??"";const isLastTypedValue=lastTypedTextFormatValueRef.current!==null&&value===lastTypedTextFormatValueRef.current;const bothHaveContent=safeValue!==""&&safeProp!=="";const oneIsPrefixOfOther=safeProp.startsWith(safeValue)||safeValue.startsWith(safeProp);const skipSyncUserTyping=isTextFormat&&propValue!==value&&(isLastTypedValue||bothHaveContent&&oneIsPrefixOfOther);if(keepInvalidTextRef.current&&(!propValue||propValue.trim()==="")){keepInvalidTextRef.current=false;}else if(skipSyncUserTyping){return}else if(propValue===value||(propValue??"")===(value??"")){keepInvalidTextRef.current=false;lastTypedTextFormatValueRef.current=null;return}else {setValue(propValue);keepInvalidTextRef.current=false;lastTypedTextFormatValueRef.current=null;}}},[propValue,isTextFormat,value]);useOnMountEffect(()=>{const skipValidation=dateFormat==="LL"&&propValue;if(!skipValidation&&!isValid()){updateDateAsInvalid();}});const handleFocus=e=>{if(onFocus){onFocus(e);}};const pendingValidationRef=React.useRef(false);const validateInput=React.useCallback(()=>{lastTypedTextFormatValueRef.current=null;const date=processDate(value);if(date){const modifiersResult=processModifiers(date,value);if(!modifiersResult.disabled){updateDate(date,value);}else {if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDate(date,value);}else {setValue(propValue);}}}else if(value&&value.trim()!==""){if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDateAsInvalid();}else {setValue(propValue);}}else {setValue(propValue);}},[value,processDate,processModifiers,resetInvalidValueOnBlur,propValue,updateDate,updateDateAsInvalid]);const handleBlur=e=>{const movingToCalendar=e.relatedTarget instanceof HTMLElement&&e.relatedTarget.closest('[data-testid="date-picker-overlay"]')!==null;if(movingToCalendar){pendingValidationRef.current=true;if(onBlur){onBlur(e);}return}validateInput();if(onBlur){onBlur(e);}};const innerRef=React.useRef(null);const handleChange=newValue=>{setValue(newValue);const date=processDate(newValue);if(date){const modifiersResult=processModifiers(date,newValue);if(isTextFormat){lastTypedTextFormatValueRef.current=newValue;}if(!modifiersResult.disabled){updateDate(date,newValue);}else if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDate(date,newValue);}else {updateDate(date,newValue);}}else if(!resetInvalidValueOnBlur&&newValue&&newValue.trim()!==""){keepInvalidTextRef.current=true;updateDateAsInvalid();}};React.useImperativeHandle(ref,()=>{const inputElement=innerRef.current;if(!inputElement){return null}inputElement.validateInput=()=>{pendingValidationRef.current=false;validateInput();};return inputElement});return jsxs(View,{style:styles$1.container,onClick:e=>{if(!restProps.disabled&&onClick){onClick(e);}},children:[jsx(TextField,{ref:innerRef,...restProps,onBlur:handleBlur,onFocus:handleFocus,onKeyDown:onKeyDown,onChange:handleChange,disabled:restProps.disabled,placeholder:placeholder,value:value??"",testId:testId,"aria-label":ariaLabel,autoComplete:"off",type:"text",style:styles$1.textField}),jsx(PhosphorIcon,{icon:calendarIcon,color:restProps.disabled?semanticColor.core.foreground.disabled.default:semanticColor.core.foreground.instructive.default,size:"small",style:styles$1.icon})]})});const fieldPaddingInline=sizing.size_160;const iconSize=sizing.size_160;const fieldPaddingInlineEnd=fieldPaddingInline+iconSize+fieldPaddingInline;const styles$1=StyleSheet.create({container:{alignItems:"center",flexDirection:"row",justifyContent:"stretch"},icon:{pointerEvents:"none",position:"absolute",insetInlineEnd:fieldPaddingInline},textField:{width:"100%",paddingInlineStart:fieldPaddingInline,paddingInlineEnd:fieldPaddingInlineEnd}});
20
36
 
21
37
  function FocusManager(props){const{children,referenceElement,onStartFocused,onEndFocused}=props;const rootNodeRef=React.useRef(null);const focusableElementsRef=React.useRef([]);const focusableElementsInsideRef=React.useRef([]);const nextFocusableElementRef=React.useRef(null);const getFocusableElements=React.useCallback(()=>{return findFocusableNodes(document)},[]);const getReferenceIndex=React.useCallback(()=>{if(!referenceElement){return -1}return focusableElementsRef.current.indexOf(referenceElement)},[referenceElement]);const getNextFocusableElement=React.useCallback(()=>{const referenceIndex=getReferenceIndex();if(referenceIndex>=0){const nextElementIndex=referenceIndex<focusableElementsRef.current.length-1?referenceIndex+1:0;return focusableElementsRef.current[nextElementIndex]}return undefined},[getReferenceIndex]);React.useEffect(()=>{focusableElementsRef.current=getFocusableElements();nextFocusableElementRef.current=getNextFocusableElement();const handleKeydownReferenceElement=e=>{if(e.key==="Tab"&&!e.shiftKey){if(rootNodeRef.current){focusableElementsInsideRef.current=findFocusableNodes(rootNodeRef.current);}if(focusableElementsInsideRef.current.length>0){e.preventDefault();focusableElementsInsideRef.current[0]?.focus();}}};const handleKeydownNextFocusableElement=e=>{if(e.key==="Tab"&&e.shiftKey){if(rootNodeRef.current){focusableElementsInsideRef.current=findFocusableNodes(rootNodeRef.current);}if(focusableElementsInsideRef.current.length>0){e.preventDefault();const lastIndex=focusableElementsInsideRef.current.length-1;focusableElementsInsideRef.current[lastIndex]?.focus();}}};if(referenceElement){referenceElement.addEventListener("keydown",handleKeydownReferenceElement,true);}if(nextFocusableElementRef.current){nextFocusableElementRef.current.addEventListener("keydown",handleKeydownNextFocusableElement,true);}return ()=>{if(referenceElement){referenceElement.removeEventListener("keydown",handleKeydownReferenceElement,true);}if(nextFocusableElementRef.current){nextFocusableElementRef.current.removeEventListener("keydown",handleKeydownNextFocusableElement,true);}}},[referenceElement,getNextFocusableElement,getFocusableElements]);const setComponentRootNode=React.useCallback(node=>{if(!node){return}rootNodeRef.current=node;focusableElementsInsideRef.current=findFocusableNodes(node);},[]);const handleFocusPreviousFocusableElement=React.useCallback(()=>{if(referenceElement){referenceElement.focus();}if(onStartFocused){onStartFocused();}},[referenceElement,onStartFocused]);const handleFocusNextFocusableElement=React.useCallback(()=>{if(nextFocusableElementRef.current){nextFocusableElementRef.current.focus();}if(onEndFocused){onEndFocused();}},[onEndFocused]);return jsxs(React.Fragment,{children:[jsx("div",{tabIndex:0,"data-testid":"focus-sentinel-prev",onFocus:handleFocusPreviousFocusableElement,style:{position:"fixed"}}),jsx("div",{"data-testid":"date-picker-overlay",ref:setComponentRootNode,children:children}),jsx("div",{tabIndex:0,"data-testid":"focus-sentinel-next",onFocus:handleFocusNextFocusableElement,style:{position:"fixed"}})]})}
22
38
 
23
- const DEFAULT_STYLE={background:semanticColor.core.background.base.default,borderRadius:border.radius.radius_040,border:`solid ${border.width.thin} ${semanticColor.core.border.neutral.subtle}`,boxShadow:boxShadow.mid};const BASE_CONTAINER_STYLES={fontFamily:font.family.sans,padding:sizing.size_100};const OUT_OF_BOUNDARIES_STYLES={visibility:"hidden"};const DatePickerOverlay=({children,referenceElement,onClose,style=DEFAULT_STYLE})=>{if(!referenceElement){return null}const modalHost=maybeGetPortalMountedModalHostElement(referenceElement)||document.querySelector("body");if(!modalHost){return null}return createPortal(jsx(FocusManager,{referenceElement:referenceElement,onEndFocused:onClose,children:jsx(Popper,{referenceElement:referenceElement,placement:"bottom-start",strategy:"fixed",modifiers:[{name:"preventOverflow",options:{rootBoundary:"viewport"}}],children:({placement,ref,style:popperStyle,isReferenceHidden,hasPopperEscaped})=>{const isTestEnvironment=typeof window!=="undefined"&&window.navigator.userAgent.includes("jsdom");const outOfBoundaries=!isTestEnvironment&&(isReferenceHidden||hasPopperEscaped);const combinedStyles={...BASE_CONTAINER_STYLES,...popperStyle,...style,...outOfBoundaries&&OUT_OF_BOUNDARIES_STYLES};return jsx("div",{ref:ref,style:combinedStyles,"data-placement":placement,children:children})}})}),modalHost)};
39
+ const DEFAULT_STYLE={background:semanticColor.core.background.base.default,borderRadius:border.radius.radius_040,border:`solid ${border.width.thin} ${semanticColor.core.border.neutral.subtle}`,boxShadow:boxShadow.mid};const BASE_CONTAINER_STYLES={fontFamily:font.family.sans,padding:sizing.size_100};const OUT_OF_BOUNDARIES_STYLES={visibility:"hidden"};const DatePickerOverlay=({children,referenceElement,onClose,dir="ltr",style=DEFAULT_STYLE})=>{if(!referenceElement){return null}const placement=dir==="rtl"?"bottom-end":"bottom-start";const modalHost=maybeGetPortalMountedModalHostElement(referenceElement)||document.querySelector("body");if(!modalHost){return null}return createPortal(jsx(FocusManager,{referenceElement:referenceElement,onEndFocused:onClose,children:jsx(Popper,{referenceElement:referenceElement,placement:placement,strategy:"fixed",modifiers:[{name:"preventOverflow",options:{rootBoundary:"viewport"}}],children:({placement,ref,style:popperStyle,isReferenceHidden,hasPopperEscaped})=>{const isTestEnvironment=typeof window!=="undefined"&&window.navigator.userAgent.includes("jsdom");const outOfBoundaries=!isTestEnvironment&&(isReferenceHidden||hasPopperEscaped);const combinedStyles={...BASE_CONTAINER_STYLES,...popperStyle,...style,...outOfBoundaries&&OUT_OF_BOUNDARIES_STYLES};return jsx("div",{ref:ref,style:combinedStyles,"data-placement":placement,children:children})}})}),modalHost)};
24
40
 
25
- const customRootStyle={"--rdp-accent-color":semanticColor.core.border.instructive.default};const DatePicker=props=>{const{locale,updateDate,dateFormat,disabled,id,maxDate,minDate,inputAriaLabel,placeholder,selectedDate,style,closeOnSelect=true,resetInvalidValueOnBlur=true,footer}=props;const[showOverlay,setShowOverlay]=React.useState(false);const[currentDate,setCurrentDate]=React.useState(selectedDate);const[displayMonth,setDisplayMonth]=React.useState(selectedDate?TemporalLocaleUtils.temporalDateToJsDate(selectedDate):undefined);const datePickerInputRef=React.useRef(null);const datePickerRef=React.useRef(null);const refWrapper=React.useRef(null);const open=React.useCallback(()=>{if(!disabled){setShowOverlay(true);}},[disabled]);const close=React.useCallback(()=>{setShowOverlay(false);datePickerInputRef.current?.validateInput?.();},[]);const computedLocale=locale??enUS;const dir=refWrapper.current?.closest("[dir]")?.getAttribute("dir")||"ltr";React.useEffect(()=>{setCurrentDate(selectedDate);if(selectedDate){setDisplayMonth(TemporalLocaleUtils.temporalDateToJsDate(selectedDate));}},[selectedDate]);React.useEffect(()=>{const handleClick=e=>{const target=e.target;const thisElement=refWrapper.current;const dayPickerCalendar=datePickerRef.current;const isElement=target instanceof Element;const inThisElement=isElement&&thisElement?.contains(target);const inCalendar=isElement&&dayPickerCalendar?.contains(target);const inPortal=isElement&&target.closest("[data-placement]")!==null;const shouldClose=showOverlay&&closeOnSelect&&thisElement&&!inThisElement&&!inCalendar&&!inPortal;if(shouldClose){setShowOverlay(false);}};document.addEventListener("mouseup",handleClick);return ()=>{document.removeEventListener("mouseup",handleClick);}},[showOverlay,closeOnSelect]);const isLeavingDropdown=e=>{const dayPickerCalendar=datePickerRef.current;if(!dayPickerCalendar){return true}if(e.relatedTarget instanceof Node){return !dayPickerCalendar.contains(e.relatedTarget)}return true};const handleInputBlur=e=>{if(isLeavingDropdown(e)){close();}};const handleInputChange=(selectedDate,modifiers)=>{if(!selectedDate){setCurrentDate(null);updateDate(null);return}const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(selectedDate);const isDisabled=typeof modifiers.disabled==="function"?modifiers.disabled(selectedDate):modifiers.disabled;if(isDisabled){updateDate(wrappedDate);return}setCurrentDate(wrappedDate);setDisplayMonth(selectedDate);updateDate(wrappedDate);};const handleKeyDown=e=>{if(e.key==="Escape"){close();datePickerInputRef.current?.focus();}if(e.key==="ArrowDown"&&!showOverlay){e.preventDefault();open();}if(e.key==="Enter"){e.preventDefault();if(showOverlay){if(closeOnSelect){close();}}else {open();}}};const RootWithEsc=props=>{const{onKeyDown,rootRef:_,...rest}=props;return jsx("div",{...rest,tabIndex:-1,onKeyDown:e=>{onKeyDown?.(e);if(e.key==="Escape"){close();datePickerInputRef.current?.focus();}}})};const handleDayClick=(date,{disabled})=>{if(disabled||!date){return}datePickerInputRef.current?.focus();const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(date);setCurrentDate(wrappedDate);setDisplayMonth(date);updateDate(wrappedDate);setShowOverlay(!closeOnSelect);};const renderInput=modifiers=>{const selectedDateAsValue=currentDate?TemporalLocaleUtils.formatDate(currentDate,dateFormat,computedLocale):"";return jsx(DatePickerInput,{onBlur:handleInputBlur,onFocus:open,onClick:open,onChange:handleInputChange,onKeyDown:handleKeyDown,"aria-label":inputAriaLabel,disabled:disabled,id:id,placeholder:placeholder,value:selectedDateAsValue,ref:datePickerInputRef,dateFormat:dateFormat,locale:computedLocale.code,parseDate:TemporalLocaleUtils.parseDateToJsDate,getModifiersForDay:TemporalLocaleUtils.getModifiersForDay,modifiers:modifiers,resetInvalidValueOnBlur:resetInvalidValueOnBlur,testId:id&&`${id}-input`})};const maybeRenderFooter=()=>{if(!footer){return null}return jsx(View,{testId:"date-picker-footer",style:styles.footer,children:footer({close})})};const selectedDateValue=currentDate?TemporalLocaleUtils.temporalDateToJsDate(currentDate):undefined;const minDateToShow=minDate&&selectedDateValue?Temporal.PlainDate.compare(minDate,currentDate)<0?TemporalLocaleUtils.temporalDateToJsDate(minDate):selectedDateValue:minDate?TemporalLocaleUtils.temporalDateToJsDate(minDate):undefined;const modifiers={selected:selectedDateValue,disabled:date=>{const temporalDate=TemporalLocaleUtils.jsDateToTemporalDate(date);return minDate&&Temporal.PlainDate.compare(temporalDate,minDate)<0||maxDate&&Temporal.PlainDate.compare(temporalDate,maxDate)>0||false}};return jsxs(View,{style:[styles.wrapper,style],ref:refWrapper,children:[renderInput(modifiers),showOverlay&&jsx(DatePickerOverlay,{referenceElement:datePickerInputRef.current,onClose:close,children:jsxs(View,{ref:datePickerRef,children:[jsx(DayPicker,{mode:"single",selected:selectedDateValue,month:displayMonth,onMonthChange:setDisplayMonth,startMonth:minDateToShow??undefined,endMonth:maxDate?TemporalLocaleUtils.temporalDateToJsDate(maxDate):undefined,modifiers:modifiers,onDayClick:handleDayClick,components:{Root:RootWithEsc},locale:computedLocale,dir:dir,styles:{root:{...customRootStyle},nav:{width:"auto"}}}),maybeRenderFooter()]})})]})};DatePicker.defaultProps={closeOnSelect:true};const styles=StyleSheet.create({wrapper:{width:225,height:40},footer:{margin:sizing.size_120,marginBlockStart:0}});
41
+ const customRootStyle={"--rdp-accent-color":semanticColor.core.border.instructive.default};const DatePicker=props=>{const{locale,updateDate,dateFormat,disabled,id,maxDate,minDate,inputAriaLabel,placeholder,selectedDate,style,closeOnSelect=true,resetInvalidValueOnBlur=true,footer}=props;const[showOverlay,setShowOverlay]=React.useState(false);const[currentDate,setCurrentDate]=React.useState(selectedDate);const datePickerInputRef=React.useRef(null);const datePickerRef=React.useRef(null);const refWrapper=React.useRef(null);const skipNextOpenRef=React.useRef(false);const{handleEscapeKeyDown}=useEscapeKeyupCapture();const{displayMonth,setDisplayMonth,displayMonthRef,inputDrivenMonthRef,setDisplayMonthAndRefs}=useDisplayMonth({selectedDate});const open=React.useCallback(()=>{if(skipNextOpenRef.current){skipNextOpenRef.current=false;return}if(!disabled){if(selectedDate!=null){const jsDate=TemporalLocaleUtils.temporalDateToJsDate(selectedDate);setDisplayMonthAndRefs(jsDate);}else {displayMonthRef.current=displayMonthRef.current??displayMonth;}setShowOverlay(true);}},[disabled,displayMonth,displayMonthRef,selectedDate,setDisplayMonthAndRefs,skipNextOpenRef]);const{handleInputChange,clearInputDrivenMonth}=useOverlayMonthFromInput({inputDrivenMonthRef,setDisplayMonth,setDisplayMonthAndRefs,setCurrentDate,updateDate,dateFormat,localeCode:locale?.code});const close=React.useCallback(()=>{clearInputDrivenMonth();if(selectedDate!=null){const jsDate=TemporalLocaleUtils.temporalDateToJsDate(selectedDate);setDisplayMonthAndRefs(jsDate);}else {setDisplayMonthAndRefs(null);}setShowOverlay(false);datePickerInputRef.current?.validateInput?.();},[selectedDate,setDisplayMonthAndRefs,clearInputDrivenMonth,datePickerInputRef]);useCloseOnOutsideClick({refWrapper,datePickerRef,showOverlay,closeOnSelect,close});useSelectedDateSync({selectedDate,setCurrentDate,setDisplayMonthAndRefs});const computedLocale=locale??enUS;const selectedDateValue=currentDate?TemporalLocaleUtils.temporalDateToJsDate(currentDate):undefined;const modifiers=useDatePickerModifiers({selectedDateValue,minDate,maxDate});const formatDateForInput=useFormatDateForInput({dateFormat,locale:computedLocale});const dir=refWrapper.current?.closest("[dir]")?.getAttribute("dir")||"ltr";const handleMonthChange=React.useCallback(newMonth=>{clearInputDrivenMonth();setDisplayMonthAndRefs(newMonth);},[clearInputDrivenMonth,setDisplayMonthAndRefs]);const isLeavingDropdown=e=>{const dayPickerCalendar=datePickerRef.current;if(!dayPickerCalendar){return true}if(e.relatedTarget instanceof Node){return !dayPickerCalendar.contains(e.relatedTarget)}return true};const handleInputBlur=e=>{if(isLeavingDropdown(e)){close();}};const onEscapeCloseOverlay=React.useCallback(()=>{skipNextOpenRef.current=true;close();datePickerInputRef.current?.focus();},[close,skipNextOpenRef,datePickerInputRef]);const handleKeyDown=e=>{if(e.key==="Escape"){if(showOverlay){handleEscapeKeyDown(e,onEscapeCloseOverlay);}}if(e.key==="ArrowDown"&&!showOverlay){e.preventDefault();skipNextOpenRef.current=false;open();}if(e.key==="Enter"){e.preventDefault();if(showOverlay){if(closeOnSelect){close();}}else {skipNextOpenRef.current=false;open();}}};const RootWithEsc=React.useCallback(props=>{const{onKeyDown,rootRef:_,...rest}=props;return jsx("div",{...rest,tabIndex:-1,onKeyDown:e=>{onKeyDown?.(e);if(e.key==="Escape"){handleEscapeKeyDown(e,onEscapeCloseOverlay);}}})},[handleEscapeKeyDown,onEscapeCloseOverlay]);const dayPickerComponents=React.useMemo(()=>({Root:RootWithEsc}),[RootWithEsc]);const handleDayClick=React.useCallback((date,{disabled})=>{if(disabled||!date){return}datePickerInputRef.current?.focus();const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(date);setCurrentDate(wrappedDate);const monthDate=new Date(date);clearInputDrivenMonth();setDisplayMonthAndRefs(monthDate);updateDate(wrappedDate);setShowOverlay(!closeOnSelect);},[updateDate,closeOnSelect,setDisplayMonthAndRefs,datePickerInputRef,clearInputDrivenMonth]);const renderInput=inputModifiers=>{const selectedDateAsValue=formatDateForInput(currentDate);return jsx(DatePickerInput,{onBlur:handleInputBlur,onFocus:open,onClick:open,onChange:handleInputChange,onKeyDown:handleKeyDown,"aria-label":inputAriaLabel,disabled:disabled,id:id,placeholder:placeholder,value:selectedDateAsValue,ref:datePickerInputRef,dateFormat:dateFormat,locale:computedLocale.code,parseDate:TemporalLocaleUtils.parseDateToJsDate,getModifiersForDay:TemporalLocaleUtils.getModifiersForDay,modifiers:inputModifiers,resetInvalidValueOnBlur:resetInvalidValueOnBlur,testId:id&&`${id}-input`})};const maybeRenderFooter=()=>{if(!footer){return null}return jsx(View,{testId:"date-picker-footer",style:styles.footer,children:footer({close})})};const minDateToShow=minDate&&selectedDateValue?Temporal.PlainDate.compare(minDate,currentDate)<0?TemporalLocaleUtils.temporalDateToJsDate(minDate):selectedDateValue:minDate?TemporalLocaleUtils.temporalDateToJsDate(minDate):undefined;const dayPickerEndMonth=React.useMemo(()=>maxDate?TemporalLocaleUtils.temporalDateToJsDate(maxDate):undefined,[maxDate]);const dayPickerStyles=React.useMemo(()=>({root:{...customRootStyle},nav:{width:"auto"}}),[]);const inputDrivenMonth=inputDrivenMonthRef.current;const isInputDriven=inputDrivenMonth!=null;const selectedDateAsJs=selectedDate!=null?TemporalLocaleUtils.temporalDateToJsDate(selectedDate):undefined;const baseMonth=displayMonthRef.current??(showOverlay&&selectedDateAsJs?selectedDateAsJs:undefined)??displayMonth??selectedDateValue??new Date;const firstOfBaseMonth=new Date(baseMonth.getFullYear(),baseMonth.getMonth(),1);const pickerKey=isInputDriven?`input-${inputDrivenMonth.getTime()}`:`picker-${baseMonth.getTime()}`;const inputDrivenMonthMs=inputDrivenMonth?.getTime();const firstOfBaseMonthMs=firstOfBaseMonth.getTime();const dayPickerMonthProps=React.useMemo(()=>{if(isInputDriven&&inputDrivenMonthMs!=null){const d=new Date(inputDrivenMonthMs);return {month:new Date(d.getFullYear(),d.getMonth(),1),onMonthChange:handleMonthChange}}return {defaultMonth:new Date(firstOfBaseMonthMs)}},[isInputDriven,inputDrivenMonthMs,firstOfBaseMonthMs,handleMonthChange]);return jsxs(View,{style:style,ref:refWrapper,children:[renderInput(modifiers),showOverlay&&jsx(DatePickerOverlay,{referenceElement:datePickerInputRef.current,onClose:close,dir:dir==="rtl"?"rtl":"ltr",children:jsxs(View,{ref:datePickerRef,children:[jsx(DayPicker,{mode:"single",selected:selectedDateValue,...dayPickerMonthProps,startMonth:minDateToShow??undefined,endMonth:dayPickerEndMonth,modifiers:modifiers,onDayClick:handleDayClick,components:dayPickerComponents,locale:computedLocale,dir:dir,styles:dayPickerStyles},pickerKey),maybeRenderFooter()]})})]})};DatePicker.defaultProps={closeOnSelect:true};const styles=StyleSheet.create({footer:{margin:sizing.size_120,marginBlockStart:0}});
26
42
 
27
43
  export { DatePicker, TemporalLocaleUtils };
@@ -0,0 +1,19 @@
1
+ import * as React from "react";
2
+ type RefsForOutsideClick = {
3
+ /** Wrapper that contains the input (and is the "inside" boundary). */
4
+ refWrapper: React.RefObject<HTMLDivElement | null>;
5
+ /** Element that contains the calendar (may be inside a portal). */
6
+ datePickerRef: React.RefObject<HTMLElement | null>;
7
+ };
8
+ type Params = RefsForOutsideClick & {
9
+ showOverlay: boolean;
10
+ closeOnSelect: boolean;
11
+ close: () => void;
12
+ };
13
+ /**
14
+ * Subscribes to document mouseup and closes the overlay when the click is outside
15
+ * the wrapper and outside the calendar (including portaled overlay). Clear boundary:
16
+ * only handles outside-click-to-close; does not manage overlay state.
17
+ */
18
+ export declare function useCloseOnOutsideClick({ refWrapper, datePickerRef, showOverlay, closeOnSelect, close, }: Params): void;
19
+ export {};
@@ -0,0 +1,14 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import type { CustomModifiers } from "../util/types";
3
+ type Params = {
4
+ /** Selected date as JS Date for react-day-picker, or undefined if none. */
5
+ selectedDateValue: Date | undefined;
6
+ minDate?: Temporal.PlainDate | null;
7
+ maxDate?: Temporal.PlainDate | null;
8
+ };
9
+ /**
10
+ * Pure derivation: returns the modifiers object for react-day-picker (selected day
11
+ * and disabled function based on min/max). No refs, no side effects.
12
+ */
13
+ export declare function useDatePickerModifiers({ selectedDateValue, minDate, maxDate, }: Params): Partial<CustomModifiers>;
14
+ export {};
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+ import { Temporal } from "temporal-polyfill";
3
+ type SetDisplayMonthAndRefs = (month: Date | null) => void;
4
+ type Params = {
5
+ /** Initial display month when selectedDate is set; used for sync when selectedDate changes. */
6
+ selectedDate: Temporal.PlainDate | null | undefined;
7
+ };
8
+ /**
9
+ * Manages which month the calendar overlay shows: state, refs for synchronous
10
+ * reads (open/close/first render), and input-driven month when user is typing.
11
+ * Exposes setDisplayMonthAndRefs for open/close/input/day-click to call.
12
+ * Big but cohesive; open/close/input/day-click refactor to call this API.
13
+ */
14
+ export declare function useDisplayMonth({ selectedDate }: Params): {
15
+ displayMonth: Date | undefined;
16
+ setDisplayMonth: React.Dispatch<React.SetStateAction<Date | undefined>>;
17
+ displayMonthRef: React.MutableRefObject<Date | undefined>;
18
+ inputDrivenMonthRef: React.MutableRefObject<Date | null>;
19
+ setDisplayMonthAndRefs: SetDisplayMonthAndRefs;
20
+ };
21
+ export {};
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+ export type HandleEscapeKeyDown = (e: React.KeyboardEvent | KeyboardEvent, onHandled?: () => void) => void;
3
+ /**
4
+ * Provides a single Escape keydown handler that:
5
+ * 1. Stops keydown propagation
6
+ * 2. Marks Escape as "handled" so a keyup listener can stop keyup propagation (e.g. so a parent modal doesn't also close)
7
+ * 3. Runs your callback (e.g. close overlay, focus input)
8
+ *
9
+ * Call this from your keydown handlers (input, calendar root, etc.) when the user presses Escape.
10
+ * The hook registers a keyup listener in the capture phase; when it sees Escape and you've already
11
+ * called handleEscapeKeyDown for that keypress, it stops keyup propagation and clears the internal state.
12
+ */
13
+ export declare function useEscapeKeyupCapture(): {
14
+ handleEscapeKeyDown: HandleEscapeKeyDown;
15
+ };
@@ -0,0 +1,12 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import type { Locale } from "react-day-picker/locale";
3
+ type Params = {
4
+ dateFormat?: string;
5
+ locale?: Locale;
6
+ };
7
+ /**
8
+ * Returns a stable callback that formats the current date for the input field.
9
+ * Uses dateFormat and locale; returns "" for null/undefined date.
10
+ */
11
+ export declare function useFormatDateForInput({ dateFormat, locale, }: Params): (date: Temporal.PlainDate | null | undefined) => string;
12
+ export {};
@@ -0,0 +1,26 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import * as React from "react";
3
+ import type { CustomModifiers } from "../util/types";
4
+ type SetDisplayMonthAndRefs = (month: Date | null) => void;
5
+ export type HandleInputChange = (dateFromInput: Date | null | undefined, modifiers: Partial<CustomModifiers>, inputValue?: string) => void;
6
+ type Params = {
7
+ inputDrivenMonthRef: React.MutableRefObject<Date | null>;
8
+ setDisplayMonth: React.Dispatch<React.SetStateAction<Date | undefined>>;
9
+ setDisplayMonthAndRefs: SetDisplayMonthAndRefs;
10
+ setCurrentDate: React.Dispatch<React.SetStateAction<Temporal.PlainDate | null | undefined>>;
11
+ updateDate: (date: Temporal.PlainDate | null) => void;
12
+ dateFormat: string | undefined;
13
+ localeCode: string | undefined;
14
+ };
15
+ /**
16
+ * Encapsulates "input-driven overlay month" logic: while the user types, the
17
+ * calendar month follows the input; when they commit a date (or we clear),
18
+ * the overlay month is no longer driven by input so prev/next buttons work.
19
+ * Returns handleInputChange (for the input's onChange) and clearInputDrivenMonth
20
+ * (call when closing, changing month via nav, or selecting a day).
21
+ */
22
+ export declare function useOverlayMonthFromInput({ inputDrivenMonthRef, setDisplayMonth, setDisplayMonthAndRefs, setCurrentDate, updateDate, dateFormat, localeCode, }: Params): {
23
+ handleInputChange: HandleInputChange;
24
+ clearInputDrivenMonth: () => void;
25
+ };
26
+ export {};
@@ -0,0 +1,17 @@
1
+ import { Temporal } from "temporal-polyfill";
2
+ import * as React from "react";
3
+ type SetDisplayMonthAndRefs = (month: Date | null) => void;
4
+ type Params = {
5
+ selectedDate: Temporal.PlainDate | null | undefined;
6
+ setCurrentDate: React.Dispatch<React.SetStateAction<Temporal.PlainDate | null | undefined>>;
7
+ setDisplayMonthAndRefs: SetDisplayMonthAndRefs;
8
+ };
9
+ /**
10
+ * Single effect: keeps currentDate in sync with selectedDate prop.
11
+ * When selectedDate identity changes, also updates display month so the calendar
12
+ * shows the right month. Uses prevSelectedDateRef so displayMonth is only
13
+ * updated when selectedDate actually changed (not overwritten by typing or by
14
+ * using the calendar’s previous/next month buttons).
15
+ */
16
+ export declare function useSelectedDateSync({ selectedDate, setCurrentDate, setDisplayMonthAndRefs, }: Params): void;
17
+ export {};
package/dist/index.js CHANGED
@@ -41,15 +41,31 @@ function _interopNamespace(e) {
41
41
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
42
42
  var calendarIcon__default = /*#__PURE__*/_interopDefaultLegacy(calendarIcon);
43
43
 
44
- const enUSLocaleCode="en-US";function formatDate(date,format,locale){const localeCode=typeof locale==="string"?locale:locale?.code??enUSLocaleCode;const formatString=Array.isArray(format)?format[0]:format;if(!formatString){return date.toLocaleString(localeCode,{year:"numeric",month:"numeric",day:"numeric"})}if(formatString==="L"){return date.toLocaleString(localeCode,{year:"numeric",month:"numeric",day:"numeric"})}if(formatString==="LL"){return date.toLocaleString(localeCode,{dateStyle:"long"})}if(formatString==="dateStyle:short"||formatString==="dateStyle:medium"||formatString==="dateStyle:long"||formatString==="dateStyle:full"){const style=formatString.split(":")[1];return date.toLocaleString(localeCode,{dateStyle:style})}if(formatString==="YYYY-MM-DD"){return date.toString()}if(formatString==="MMMM D, YYYY"||formatString==="MMM D, YYYY"){try{const monthFormat=formatString==="MMMM D, YYYY"?"long":"short";const monthName=date.toLocaleString(localeCode,{month:monthFormat});return `${monthName} ${date.day}, ${date.year}`}catch(error){return date.toString()}}if(formatString==="MM/DD/YYYY"||formatString==="M/D/YYYY"||formatString==="DD/MM/YYYY"){const shouldPad=formatString.includes("MM")||formatString.includes("DD");const month=shouldPad?String(date.month).padStart(2,"0"):String(date.month);const day=shouldPad?String(date.day).padStart(2,"0"):String(date.day);return `${month}/${day}/${date.year}`}try{const options=getOptionsForFormat(formatString);return date.toLocaleString(localeCode,options)}catch(error){console.warn(`Failed to format date with format "${formatString}" and locale "${localeCode}". Falling back to ISO format.`,error);return date.toString()}}function parseDate(str,format,locale){if(!str||str.trim()===""){return undefined}const formats=Array.isArray(format)?format:[format||"L"];try{return temporalPolyfill.Temporal.PlainDate.from(str)}catch{}for(const fmt of formats){try{const parsed=parseWithFormat(str,fmt,locale);if(parsed){return parsed}}catch{continue}}return undefined}const getModifiersForDay=(day,modifiers)=>{const matchedModifiers=[];for(const[modifierName,matcher]of Object.entries(modifiers)){if(!matcher){continue}if(typeof matcher==="function"){if(matcher(day)){matchedModifiers.push(modifierName);}}else if(matcher instanceof Date){if(day.getFullYear()===matcher.getFullYear()&&day.getMonth()===matcher.getMonth()&&day.getDate()===matcher.getDate()){matchedModifiers.push(modifierName);}}}return matchedModifiers};function temporalDateToJsDate(date){return new Date(date.year,date.month-1,date.day)}function jsDateToTemporalDate(date){return temporalPolyfill.Temporal.PlainDate.from({year:date.getFullYear(),month:date.getMonth()+1,day:date.getDate()})}function parseDateToJsDate(value,format,locale){if(value instanceof Date){return value}const temporalDate=parseDate(value,format,locale||undefined);if(temporalDate){const formatted=formatDate(temporalDate,format,locale||undefined);if(formatted===value){return temporalDateToJsDate(temporalDate)}const normalizedFormatted=formatted.replace(/\b0(\d)\b/g,"$1");const normalizedValue=value.replace(/\b0(\d)\b/g,"$1");if(normalizedFormatted===normalizedValue){return temporalDateToJsDate(temporalDate)}if(value===temporalDate.toString()){return temporalDateToJsDate(temporalDate)}if(format==="LL"){const normalizedFormatted=formatted.replace(/\s+/g," ").trim().toLowerCase();const normalizedValue=value.replace(/\s+/g," ").trim().toLowerCase();if(normalizedFormatted===normalizedValue){return temporalDateToJsDate(temporalDate)}return temporalDateToJsDate(temporalDate)}return undefined}return undefined}function getMonths(locale){const format=new Intl.DateTimeFormat(locale||enUSLocaleCode,{month:"long"});const formatShort=new Intl.DateTimeFormat(locale||enUSLocaleCode,{month:"short"});const months=[];for(let i=0;i<12;i++){const date=new Date(2021,i,15);months.push([format.format(date),formatShort.format(date)]);}return months}function getOptionsForFormat(format){const options={};if(format.includes("YYYY")){options.year="numeric";}else if(format.includes("YY")){options.year="2-digit";}if(format.includes("MMMM")){options.month="long";}else if(format.includes("MMM")){options.month="short";}else if(format.includes("MM")){options.month="2-digit";}else if(format.includes("M")){options.month="numeric";}if(format.includes("DD")){options.day="2-digit";}else if(format.includes("D")){options.day="numeric";}if(format.includes("dddd")){options.weekday="long";}else if(format.includes("ddd")){options.weekday="short";}return options}function parseLocaleAwareDate(str,locale){const localeStr=locale||enUSLocaleCode;const cleaned=str.trim();if(!cleaned){return undefined}try{const formatter=new Intl.DateTimeFormat(localeStr,{dateStyle:"short"});const testDate=new Date(2020,0,15);const parts=formatter.formatToParts(testDate);const pattern=parts.map(p=>({type:p.type,value:p.value}));const separators=pattern.filter(p=>p.type==="literal").map(p=>p.value);const inputParts=cleaned.split(new RegExp(`[${separators.map(s=>`\\${s}`).join("")}]`));if(inputParts.length!==3){throw new Error("Not a numeric date format")}const dateComponents={};let partIndex=0;for(const patternPart of pattern){if(patternPart.type==="literal"){continue}const value=parseInt(inputParts[partIndex],10);if(isNaN(value)){throw new Error("Not a numeric date format")}dateComponents[patternPart.type]=value;partIndex++;}if(!dateComponents.year||!dateComponents.month||!dateComponents.day||dateComponents.month<1||dateComponents.month>12||dateComponents.day<1||dateComponents.day>31||dateComponents.year<1e3||dateComponents.year>9999){throw new Error("Invalid date range")}return temporalPolyfill.Temporal.PlainDate.from({year:dateComponents.year,month:dateComponents.month,day:dateComponents.day})}catch{return parseTextDate(cleaned,localeStr)}}function parseTextDate(str,locale){try{const months=getMonths(locale);const numbers=str.match(/\d+/g);if(!numbers||numbers.length<2){return undefined}let monthIndex=-1;const lowerStr=str.toLowerCase();for(let i=0;i<months.length;i++){const[longName,shortName]=months[i];if(lowerStr.includes(longName.toLowerCase())||lowerStr.includes(shortName.toLowerCase())){monthIndex=i+1;break}}if(monthIndex===-1){return undefined}let day;let year;const num1=parseInt(numbers[0],10);const num2=parseInt(numbers[1],10);if(num1>31){year=num1;day=num2;}else if(num2>31||num2.toString().length===4){day=num1;year=num2;}else {day=num1;year=num2;}if(day<1||day>31||monthIndex<1||monthIndex>12||year<1e3||year>9999){return undefined}return temporalPolyfill.Temporal.PlainDate.from({year,month:monthIndex,day})}catch{return undefined}}function parseWithFormat(str,format,locale){if(!format){return undefined}if(format==="L"||format==="LL"||format.startsWith("dateStyle:")){return parseLocaleAwareDate(str,locale)}if(format==="M/D/YYYY"||format==="M-D-YYYY"||format==="MM/DD/YYYY"||format==="MM-DD-YYYY"){const separator=format.includes("/")?"/":"-";const parts=str.split(separator);if(parts.length===3){const month=parseInt(parts[0],10);const day=parseInt(parts[1],10);const year=parseInt(parts[2],10);if(isNaN(month)||isNaN(day)||isNaN(year)||month<1||month>12||day<1||day>31||year<1e3||year>9999){return undefined}try{return temporalPolyfill.Temporal.PlainDate.from({year,month,day})}catch{return undefined}}}if(format==="MMMM D, YYYY"||format==="MMM D, YYYY"){try{const cleaned=str.trim();const localeStr=locale||enUSLocaleCode;const parts=cleaned.split(",");if(parts.length===2){const[monthDay,yearStr]=parts;const year=parseInt(yearStr.trim(),10);if(year<1e3||year>9999){return undefined}const months=getMonths(localeStr).map(m=>m[0]);const monthDayParts=monthDay.trim().split(" ");if(monthDayParts.length===2){const monthName=monthDayParts[0];const day=parseInt(monthDayParts[1],10);const monthIndex=months.findIndex(m=>m.toLowerCase()===monthName.toLowerCase()||m.slice(0,3).toLowerCase()===monthName.toLowerCase());if(monthIndex>=0&&!isNaN(day)&&!isNaN(year)){return temporalPolyfill.Temporal.PlainDate.from({year,month:monthIndex+1,day})}}}}catch{return undefined}}return undefined}const startOfIsoWeek=date=>{const dayOfWeek=date.dayOfWeek;return date.subtract({days:dayOfWeek-1})};const startOfDay=date=>{const result=new Date(date);result.setHours(0,0,0,0);return result};const endOfDay=date=>{const result=new Date(date);result.setHours(23,59,59,999);return result};const TemporalLocaleUtils={formatDate,parseDate,parseDateToJsDate,startOfIsoWeek,startOfDay,endOfDay,temporalDateToJsDate,jsDateToTemporalDate,getModifiersForDay};
44
+ function useCloseOnOutsideClick({refWrapper,datePickerRef,showOverlay,closeOnSelect,close}){React__namespace.useEffect(()=>{const handleClick=e=>{const target=e.target;const thisElement=refWrapper.current;const dayPickerCalendar=datePickerRef.current;const isElement=target instanceof Element;const inThisElement=isElement&&thisElement?.contains(target);const inCalendar=isElement&&dayPickerCalendar?.contains(target);const inPortal=isElement&&target.closest("[data-placement]")!==null;const shouldClose=showOverlay&&closeOnSelect&&thisElement&&!inThisElement&&!inCalendar&&!inPortal;if(shouldClose){close();}};document.addEventListener("mouseup",handleClick);return ()=>{document.removeEventListener("mouseup",handleClick);}},[refWrapper,datePickerRef,showOverlay,closeOnSelect,close]);}
45
45
 
46
- const DatePickerInput=React__namespace.forwardRef((props,ref)=>{const{value:propValue,onBlur,onClick,onFocus,onKeyDown,onChange,dateFormat,locale=enUSLocaleCode,modifiers,getModifiersForDay,parseDate,placeholder,testId,resetInvalidValueOnBlur=true,["aria-label"]:ariaLabel,...restProps}=props;const[value,setValue]=React__namespace.useState(propValue);const lastPropValueRef=React__namespace.useRef(propValue);const keepInvalidTextRef=React__namespace.useRef(false);const processModifiers=React__namespace.useCallback((date,value)=>{if(!getModifiersForDay||!modifiers){return {}}return getModifiersForDay(date,modifiers).reduce((obj,modifier)=>({...obj,[modifier]:true}),{})},[getModifiersForDay,modifiers]);const updateDate=React__namespace.useCallback((date,value)=>{if(onChange){onChange(date,processModifiers(date,value));}},[onChange,processModifiers]);const updateDateAsInvalid=React__namespace.useCallback(()=>{if(onChange){onChange(null,{});}},[onChange]);const processDate=React__namespace.useCallback(inputValue=>{if(!inputValue||inputValue.trim()===""){return}if(!parseDate){return}const date=parseDate(inputValue,dateFormat,locale);if(!date){return}return date},[parseDate,dateFormat,locale]);const isValid=React__namespace.useCallback(()=>{const date=processDate(value);if(!date){return false}const modifiersResult=processModifiers(date,value);if(modifiersResult.disabled){return false}return true},[value,processDate,processModifiers]);React__namespace.useEffect(()=>{const propValueChanged=lastPropValueRef.current!==propValue;lastPropValueRef.current=propValue;if(propValueChanged){if(keepInvalidTextRef.current&&(!propValue||propValue.trim()==="")){keepInvalidTextRef.current=false;}else {setValue(propValue);keepInvalidTextRef.current=false;}}},[propValue]);wonderBlocksCore.useOnMountEffect(()=>{const skipValidation=dateFormat==="LL"&&propValue;if(!skipValidation&&!isValid()){updateDateAsInvalid();}});const handleFocus=e=>{if(onFocus){onFocus(e);}};const pendingValidationRef=React__namespace.useRef(false);const validateInput=React__namespace.useCallback(()=>{const date=processDate(value);if(date){const modifiersResult=processModifiers(date,value);if(!modifiersResult.disabled){updateDate(date,value);}else {if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDate(date,value);}else {setValue(propValue);}}}else if(value&&value.trim()!==""){if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDateAsInvalid();}else {setValue(propValue);}}else {setValue(propValue);}},[value,processDate,processModifiers,resetInvalidValueOnBlur,propValue,updateDate,updateDateAsInvalid]);const handleBlur=e=>{const movingToCalendar=e.relatedTarget instanceof HTMLElement&&e.relatedTarget.closest('[data-testid="date-picker-overlay"]')!==null;if(movingToCalendar){pendingValidationRef.current=true;if(onBlur){onBlur(e);}return}validateInput();if(onBlur){onBlur(e);}};const handleChange=newValue=>{setValue(newValue);const date=processDate(newValue);if(date){const modifiersResult=processModifiers(date,newValue);if(!modifiersResult.disabled){updateDate(date,newValue);}else if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDate(date,newValue);}}else if(!resetInvalidValueOnBlur&&newValue&&newValue.trim()!==""){keepInvalidTextRef.current=true;updateDateAsInvalid();}};const innerRef=React__namespace.useRef(null);React__namespace.useImperativeHandle(ref,()=>{const inputElement=innerRef.current;if(!inputElement){return null}inputElement.validateInput=()=>{if(pendingValidationRef.current){pendingValidationRef.current=false;validateInput();}};return inputElement});return jsxRuntime.jsxs(wonderBlocksCore.View,{style:styles$1.container,onClick:e=>{if(!restProps.disabled&&onClick){onClick(e);}},children:[jsxRuntime.jsx(wonderBlocksForm.TextField,{ref:innerRef,...restProps,onBlur:handleBlur,onFocus:handleFocus,onKeyDown:onKeyDown,onChange:handleChange,disabled:restProps.disabled,placeholder:placeholder,value:value??"",testId:testId,"aria-label":ariaLabel,autoComplete:"off",type:"text",style:styles$1.textField}),jsxRuntime.jsx(wonderBlocksIcon.PhosphorIcon,{icon:calendarIcon__default["default"],color:restProps.disabled?wonderBlocksTokens.semanticColor.core.foreground.disabled.default:wonderBlocksTokens.semanticColor.core.foreground.instructive.default,size:"small",style:styles$1.icon})]})});const styles$1=aphrodite.StyleSheet.create({container:{alignItems:"center",flexDirection:"row",justifyContent:"stretch"},icon:{pointerEvents:"none",position:"absolute",insetInlineEnd:wonderBlocksTokens.sizing.size_080},textField:{width:"100%"}});
46
+ const enUSLocaleCode="en-US";const TEXT_FORMAT_STRINGS=["LL","MMMM D, YYYY","MMM D, YYYY"];function isTextFormatDate(formatString){return formatString!=null&&TEXT_FORMAT_STRINGS.includes(formatString)}function normalizeDateStringForComparison(s){return s.trim().toLowerCase().replace(/\s+/g," ").replace(/[,.\u202f]/g," ").replace(/\s+/g," ").trim()}function formatDate(date,formatString,locale){const localeCode=typeof locale==="string"?locale:locale?.code??enUSLocaleCode;if(!formatString){return date.toLocaleString(localeCode,{year:"numeric",month:"numeric",day:"numeric"})}if(formatString==="L"){return date.toLocaleString(localeCode,{year:"numeric",month:"numeric",day:"numeric"})}if(formatString==="LL"){return date.toLocaleString(localeCode,{dateStyle:"long"})}if(formatString==="dateStyle:short"||formatString==="dateStyle:medium"||formatString==="dateStyle:long"||formatString==="dateStyle:full"){const style=formatString.split(":")[1];return date.toLocaleString(localeCode,{dateStyle:style})}if(formatString==="YYYY-MM-DD"){return date.toString()}if(formatString==="MMMM D, YYYY"||formatString==="MMM D, YYYY"){try{const monthFormat=formatString==="MMMM D, YYYY"?"long":"short";const monthName=date.toLocaleString(localeCode,{month:monthFormat});return `${monthName} ${date.day}, ${date.year}`}catch(error){return date.toString()}}if(formatString==="MM/DD/YYYY"||formatString==="M/D/YYYY"||formatString==="DD/MM/YYYY"){const shouldPad=formatString.includes("MM")||formatString.includes("DD");const month=shouldPad?String(date.month).padStart(2,"0"):String(date.month);const day=shouldPad?String(date.day).padStart(2,"0"):String(date.day);return `${month}/${day}/${date.year}`}try{const options=getOptionsForFormat(formatString);return date.toLocaleString(localeCode,options)}catch(error){console.warn(`Failed to format date with format "${formatString}" and locale "${localeCode}". Falling back to ISO format.`,error);return date.toString()}}function parseDate(str,formatString,locale){if(!str||str.trim()===""){return undefined}try{return temporalPolyfill.Temporal.PlainDate.from(str)}catch{}const format=formatString||"L";try{const parsed=parseWithFormat(str,format,locale);if(parsed){return parsed}}catch{}return undefined}const getModifiersForDay=(day,modifiers)=>{const matchedModifiers=[];for(const[modifierName,matcher]of Object.entries(modifiers)){if(!matcher){continue}if(typeof matcher==="function"){if(matcher(day)){matchedModifiers.push(modifierName);}}else if(matcher instanceof Date){if(day.getFullYear()===matcher.getFullYear()&&day.getMonth()===matcher.getMonth()&&day.getDate()===matcher.getDate()){matchedModifiers.push(modifierName);}}}return matchedModifiers};function temporalDateToJsDate(date){return new Date(date.year,date.month-1,date.day)}function jsDateToTemporalDate(date){return temporalPolyfill.Temporal.PlainDate.from({year:date.getFullYear(),month:date.getMonth()+1,day:date.getDate()})}function parseDateToJsDate(value,formatString,locale){if(value instanceof Date){return value}const temporalDate=parseDate(value,formatString,locale||undefined);if(temporalDate){const formatted=formatDate(temporalDate,formatString,locale||undefined);if(formatted===value){return temporalDateToJsDate(temporalDate)}const normalizedFormatted=formatted.replace(/\b0(\d)\b/g,"$1");const normalizedValue=value.replace(/\b0(\d)\b/g,"$1");if(normalizedFormatted===normalizedValue){return temporalDateToJsDate(temporalDate)}if(value===temporalDate.toString()){return temporalDateToJsDate(temporalDate)}const isTextFormat=isTextFormatDate(formatString);if(isTextFormat){const normalizedFormatted=formatted.replace(/\s+/g," ").trim().toLowerCase();const normalizedValue=value.replace(/\s+/g," ").trim().toLowerCase();if(normalizedFormatted===normalizedValue){return temporalDateToJsDate(temporalDate)}if(normalizedFormatted.startsWith(normalizedValue)||normalizedValue.startsWith(normalizedFormatted)){return temporalDateToJsDate(temporalDate)}return undefined}return undefined}return undefined}function getMonths(locale){const format=new Intl.DateTimeFormat(locale||enUSLocaleCode,{month:"long"});const formatShort=new Intl.DateTimeFormat(locale||enUSLocaleCode,{month:"short"});const months=[];for(let i=0;i<12;i++){const date=new Date(2021,i,15);months.push([format.format(date),formatShort.format(date)]);}return months}function getOptionsForFormat(format){const options={};if(format.includes("YYYY")){options.year="numeric";}else if(format.includes("YY")){options.year="2-digit";}if(format.includes("MMMM")){options.month="long";}else if(format.includes("MMM")){options.month="short";}else if(format.includes("MM")){options.month="2-digit";}else if(format.includes("M")){options.month="numeric";}if(format.includes("DD")){options.day="2-digit";}else if(format.includes("D")){options.day="numeric";}if(format.includes("dddd")){options.weekday="long";}else if(format.includes("ddd")){options.weekday="short";}return options}function parseLocaleAwareDate(str,locale){const localeStr=locale||enUSLocaleCode;const cleaned=str.trim();if(!cleaned){return undefined}try{const formatter=new Intl.DateTimeFormat(localeStr,{dateStyle:"short"});const testDate=new Date(2020,0,15);const parts=formatter.formatToParts(testDate);const pattern=parts.map(p=>({type:p.type,value:p.value}));const separators=pattern.filter(p=>p.type==="literal").map(p=>p.value);const inputParts=cleaned.split(new RegExp(`[${separators.map(s=>`\\${s}`).join("")}]`));if(inputParts.length!==3){throw new Error("Not a numeric date format")}const dateComponents={};let partIndex=0;for(const patternPart of pattern){if(patternPart.type==="literal"){continue}const value=parseInt(inputParts[partIndex],10);if(isNaN(value)){throw new Error("Not a numeric date format")}dateComponents[patternPart.type]=value;partIndex++;}if(!dateComponents.year||!dateComponents.month||!dateComponents.day||dateComponents.month<1||dateComponents.month>12||dateComponents.day<1||dateComponents.day>31||dateComponents.year<1e3||dateComponents.year>9999){throw new Error("Invalid date range")}return temporalPolyfill.Temporal.PlainDate.from({year:dateComponents.year,month:dateComponents.month,day:dateComponents.day})}catch{return parseTextDate(cleaned,localeStr)}}function parseTextDate(str,locale){try{const months=getMonths(locale);const numbers=str.match(/\d+/g)??[];const lowerStr=str.toLowerCase();let monthIndex=-1;for(let i=0;i<months.length;i++){const[longName,shortName]=months[i];if(lowerStr.includes(longName.toLowerCase())||lowerStr.includes(shortName.toLowerCase())){monthIndex=i+1;break}}if(monthIndex===-1){return undefined}const now=temporalPolyfill.Temporal.Now.plainDateISO();if(numbers.length>=2){const n1=numbers[0];const n2=numbers[1];if(n1===undefined||n2===undefined){return undefined}let day;let year;const num1=parseInt(n1,10);const num2=parseInt(n2,10);if(num1>31){year=num1;day=num2;}else if(num2>31||num2.toString().length===4){day=num1;year=num2;}else {day=num1;year=num2;}if(day<1||day>31||year<1e3||year>9999){return undefined}return temporalPolyfill.Temporal.PlainDate.from({year,month:monthIndex,day})}if(numbers.length===1){const n0=numbers[0];if(n0===undefined){return undefined}const n=parseInt(n0,10);const isYear=n>=1e3&&n<=9999;const year=isYear?n:now.year;const day=isYear?1:n>=1&&n<=31?n:1;return temporalPolyfill.Temporal.PlainDate.from({year,month:monthIndex,day})}return temporalPolyfill.Temporal.PlainDate.from({year:now.year,month:monthIndex,day:1})}catch{return undefined}}function parseWithFormat(str,format,locale){if(!format){return undefined}if(format==="L"||format==="LL"||format.startsWith("dateStyle:")){return parseLocaleAwareDate(str,locale)}if(format==="M/D/YYYY"||format==="M-D-YYYY"||format==="MM/DD/YYYY"||format==="MM-DD-YYYY"){const separator=format.includes("/")?"/":"-";const parts=str.split(separator);if(parts.length===3){const month=parseInt(parts[0],10);const day=parseInt(parts[1],10);const year=parseInt(parts[2],10);if(isNaN(month)||isNaN(day)||isNaN(year)||month<1||month>12||day<1||day>31||year<1e3||year>9999){return undefined}try{return temporalPolyfill.Temporal.PlainDate.from({year,month,day})}catch{return undefined}}}if(format==="MMMM D, YYYY"||format==="MMM D, YYYY"){try{const cleaned=str.trim();const localeStr=locale||enUSLocaleCode;const parts=cleaned.split(",");if(parts.length===2){const[monthDay,yearStr]=parts;const year=parseInt(yearStr.trim(),10);if(year<1e3||year>9999){return undefined}const months=getMonths(localeStr).map(m=>m[0]);const monthDayParts=monthDay.trim().split(" ");if(monthDayParts.length===2){const monthName=monthDayParts[0];const day=parseInt(monthDayParts[1],10);const monthIndex=months.findIndex(m=>m.toLowerCase()===monthName.toLowerCase()||m.slice(0,3).toLowerCase()===monthName.toLowerCase());if(monthIndex>=0&&!isNaN(day)&&!isNaN(year)){return temporalPolyfill.Temporal.PlainDate.from({year,month:monthIndex+1,day})}}}return parseTextDate(cleaned,localeStr)}catch{return undefined}}return undefined}const startOfIsoWeek=date=>{const dayOfWeek=date.dayOfWeek;return date.subtract({days:dayOfWeek-1})};const startOfDay=date=>{const result=new Date(date);result.setHours(0,0,0,0);return result};const endOfDay=date=>{const result=new Date(date);result.setHours(23,59,59,999);return result};const TemporalLocaleUtils={formatDate,isTextFormatDate,normalizeDateStringForComparison,parseDate,parseDateToJsDate,startOfIsoWeek,startOfDay,endOfDay,temporalDateToJsDate,jsDateToTemporalDate,getModifiersForDay};
47
+
48
+ function useDatePickerModifiers({selectedDateValue,minDate,maxDate}){return React__namespace.useMemo(()=>({selected:selectedDateValue,disabled:date=>{const temporalDate=TemporalLocaleUtils.jsDateToTemporalDate(date);return minDate&&temporalPolyfill.Temporal.PlainDate.compare(temporalDate,minDate)<0||maxDate&&temporalPolyfill.Temporal.PlainDate.compare(temporalDate,maxDate)>0||false}}),[selectedDateValue,minDate,maxDate])}
49
+
50
+ function useDisplayMonth({selectedDate}){const initialMonth=React__namespace.useMemo(()=>selectedDate!=null?TemporalLocaleUtils.temporalDateToJsDate(selectedDate):undefined,[selectedDate]);const[displayMonth,setDisplayMonth]=React__namespace.useState(initialMonth);const displayMonthRef=React__namespace.useRef(undefined);const inputDrivenMonthRef=React__namespace.useRef(null);const setDisplayMonthAndRefs=React__namespace.useCallback(month=>{if(month!==null){displayMonthRef.current=month;setDisplayMonth(month);}else {if(displayMonthRef.current!=null){setDisplayMonth(displayMonthRef.current);}displayMonthRef.current=undefined;}},[]);return {displayMonth,setDisplayMonth,displayMonthRef,inputDrivenMonthRef,setDisplayMonthAndRefs}}
51
+
52
+ function useEscapeKeyupCapture(){const handledEscapeRef=React__namespace.useRef(false);React__namespace.useEffect(()=>{const handleKeyup=e=>{if(e.key==="Escape"&&handledEscapeRef.current){e.stopPropagation();handledEscapeRef.current=false;}};window.addEventListener("keyup",handleKeyup,true);return ()=>{window.removeEventListener("keyup",handleKeyup,true);}},[]);const handleEscapeKeyDown=React__namespace.useCallback((e,onHandled)=>{e.stopPropagation();handledEscapeRef.current=true;onHandled?.();},[]);return {handleEscapeKeyDown}}
53
+
54
+ function useFormatDateForInput({dateFormat,locale}){const localeCode=locale?.code??"en-US";return React__namespace.useCallback(date=>{if(date==null){return ""}return TemporalLocaleUtils.formatDate(date,dateFormat,localeCode)},[dateFormat,localeCode])}
55
+
56
+ function isTextFormatCommitComplete(inputValue,dateFromInput,dateFormat,localeCode){if(typeof inputValue!=="string"||inputValue.trim()===""){return false}const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(dateFromInput);const reparsed=TemporalLocaleUtils.parseDate(inputValue,dateFormat,localeCode??undefined);const sameDate=reparsed!=null&&temporalPolyfill.Temporal.PlainDate.compare(reparsed,wrappedDate)===0;const formatted=TemporalLocaleUtils.formatDate(wrappedDate,dateFormat,localeCode??undefined);if(typeof formatted!=="string"){return false}const inputMatchesDisplay=TemporalLocaleUtils.normalizeDateStringForComparison(formatted)===TemporalLocaleUtils.normalizeDateStringForComparison(inputValue);return sameDate&&inputMatchesDisplay}
57
+
58
+ function useOverlayMonthFromInput({inputDrivenMonthRef,setDisplayMonth,setDisplayMonthAndRefs,setCurrentDate,updateDate,dateFormat,localeCode}){const clearInputDrivenMonth=React__namespace.useCallback(()=>{inputDrivenMonthRef.current=null;},[inputDrivenMonthRef]);const handleInputChange=React__namespace.useCallback((dateFromInput,modifiers,inputValue)=>{if(!dateFromInput){setCurrentDate(null);updateDate(null);return}const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(dateFromInput);const monthDate=new Date(dateFromInput);setDisplayMonth(monthDate);const isDisabled=typeof modifiers.disabled==="function"?modifiers.disabled(dateFromInput):modifiers.disabled;if(isDisabled){inputDrivenMonthRef.current=monthDate;updateDate(wrappedDate);return}const isTextFormat=TemporalLocaleUtils.isTextFormatDate(dateFormat);if(isTextFormat&&inputValue){const isCompleteDate=isTextFormatCommitComplete(inputValue,dateFromInput,dateFormat,localeCode);if(isCompleteDate){inputDrivenMonthRef.current=null;setDisplayMonthAndRefs(monthDate);setCurrentDate(wrappedDate);updateDate(wrappedDate);}else {inputDrivenMonthRef.current=monthDate;}}else {inputDrivenMonthRef.current=null;setDisplayMonthAndRefs(monthDate);setCurrentDate(wrappedDate);updateDate(wrappedDate);}},[inputDrivenMonthRef,setDisplayMonth,setDisplayMonthAndRefs,setCurrentDate,updateDate,dateFormat,localeCode]);return {handleInputChange,clearInputDrivenMonth}}
59
+
60
+ function useSelectedDateSync({selectedDate,setCurrentDate,setDisplayMonthAndRefs}){const prevSelectedDateRef=React__namespace.useRef(null);React__namespace.useEffect(()=>{setCurrentDate(selectedDate);const key=selectedDate?.toString()??null;const willUpdateDisplayMonth=key!==prevSelectedDateRef.current;if(willUpdateDisplayMonth){prevSelectedDateRef.current=key;if(selectedDate!=null){const jsDate=TemporalLocaleUtils.temporalDateToJsDate(selectedDate);setDisplayMonthAndRefs(jsDate);}}},[selectedDate,setCurrentDate,setDisplayMonthAndRefs]);}
61
+
62
+ const DatePickerInput=React__namespace.forwardRef((props,ref)=>{const{value:propValue,onBlur,onClick,onFocus,onKeyDown,onChange,dateFormat,locale=enUSLocaleCode,modifiers,getModifiersForDay,parseDate,placeholder,testId,resetInvalidValueOnBlur=true,["aria-label"]:ariaLabel,...restProps}=props;const[value,setValue]=React__namespace.useState(propValue);const lastPropValueRef=React__namespace.useRef(propValue);const keepInvalidTextRef=React__namespace.useRef(false);const lastTypedTextFormatValueRef=React__namespace.useRef(null);const processModifiers=React__namespace.useCallback((date,value)=>{if(!getModifiersForDay||!modifiers){return {}}return getModifiersForDay(date,modifiers).reduce((obj,modifier)=>({...obj,[modifier]:true}),{})},[getModifiersForDay,modifiers]);const updateDate=React__namespace.useCallback((date,inputValue)=>{if(onChange){onChange(date,processModifiers(date,inputValue),inputValue||undefined);}},[onChange,processModifiers]);const updateDateAsInvalid=React__namespace.useCallback(()=>{if(onChange){onChange(null,{});}},[onChange]);const processDate=React__namespace.useCallback(inputValue=>{if(!inputValue||inputValue.trim()===""){return}if(!parseDate){return}const date=parseDate(inputValue,dateFormat,locale);if(!date){return}return date},[parseDate,dateFormat,locale]);const isValid=React__namespace.useCallback(()=>{const date=processDate(value);if(!date){return false}const modifiersResult=processModifiers(date,value);if(modifiersResult.disabled){return false}return true},[value,processDate,processModifiers]);const isTextFormat=TemporalLocaleUtils.isTextFormatDate(dateFormat);React__namespace.useEffect(()=>{const propValueChanged=lastPropValueRef.current!==propValue;lastPropValueRef.current=propValue;if(propValueChanged){const safeProp=propValue??"";const safeValue=value??"";const isLastTypedValue=lastTypedTextFormatValueRef.current!==null&&value===lastTypedTextFormatValueRef.current;const bothHaveContent=safeValue!==""&&safeProp!=="";const oneIsPrefixOfOther=safeProp.startsWith(safeValue)||safeValue.startsWith(safeProp);const skipSyncUserTyping=isTextFormat&&propValue!==value&&(isLastTypedValue||bothHaveContent&&oneIsPrefixOfOther);if(keepInvalidTextRef.current&&(!propValue||propValue.trim()==="")){keepInvalidTextRef.current=false;}else if(skipSyncUserTyping){return}else if(propValue===value||(propValue??"")===(value??"")){keepInvalidTextRef.current=false;lastTypedTextFormatValueRef.current=null;return}else {setValue(propValue);keepInvalidTextRef.current=false;lastTypedTextFormatValueRef.current=null;}}},[propValue,isTextFormat,value]);wonderBlocksCore.useOnMountEffect(()=>{const skipValidation=dateFormat==="LL"&&propValue;if(!skipValidation&&!isValid()){updateDateAsInvalid();}});const handleFocus=e=>{if(onFocus){onFocus(e);}};const pendingValidationRef=React__namespace.useRef(false);const validateInput=React__namespace.useCallback(()=>{lastTypedTextFormatValueRef.current=null;const date=processDate(value);if(date){const modifiersResult=processModifiers(date,value);if(!modifiersResult.disabled){updateDate(date,value);}else {if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDate(date,value);}else {setValue(propValue);}}}else if(value&&value.trim()!==""){if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDateAsInvalid();}else {setValue(propValue);}}else {setValue(propValue);}},[value,processDate,processModifiers,resetInvalidValueOnBlur,propValue,updateDate,updateDateAsInvalid]);const handleBlur=e=>{const movingToCalendar=e.relatedTarget instanceof HTMLElement&&e.relatedTarget.closest('[data-testid="date-picker-overlay"]')!==null;if(movingToCalendar){pendingValidationRef.current=true;if(onBlur){onBlur(e);}return}validateInput();if(onBlur){onBlur(e);}};const innerRef=React__namespace.useRef(null);const handleChange=newValue=>{setValue(newValue);const date=processDate(newValue);if(date){const modifiersResult=processModifiers(date,newValue);if(isTextFormat){lastTypedTextFormatValueRef.current=newValue;}if(!modifiersResult.disabled){updateDate(date,newValue);}else if(!resetInvalidValueOnBlur){keepInvalidTextRef.current=true;updateDate(date,newValue);}else {updateDate(date,newValue);}}else if(!resetInvalidValueOnBlur&&newValue&&newValue.trim()!==""){keepInvalidTextRef.current=true;updateDateAsInvalid();}};React__namespace.useImperativeHandle(ref,()=>{const inputElement=innerRef.current;if(!inputElement){return null}inputElement.validateInput=()=>{pendingValidationRef.current=false;validateInput();};return inputElement});return jsxRuntime.jsxs(wonderBlocksCore.View,{style:styles$1.container,onClick:e=>{if(!restProps.disabled&&onClick){onClick(e);}},children:[jsxRuntime.jsx(wonderBlocksForm.TextField,{ref:innerRef,...restProps,onBlur:handleBlur,onFocus:handleFocus,onKeyDown:onKeyDown,onChange:handleChange,disabled:restProps.disabled,placeholder:placeholder,value:value??"",testId:testId,"aria-label":ariaLabel,autoComplete:"off",type:"text",style:styles$1.textField}),jsxRuntime.jsx(wonderBlocksIcon.PhosphorIcon,{icon:calendarIcon__default["default"],color:restProps.disabled?wonderBlocksTokens.semanticColor.core.foreground.disabled.default:wonderBlocksTokens.semanticColor.core.foreground.instructive.default,size:"small",style:styles$1.icon})]})});const fieldPaddingInline=wonderBlocksTokens.sizing.size_160;const iconSize=wonderBlocksTokens.sizing.size_160;const fieldPaddingInlineEnd=fieldPaddingInline+iconSize+fieldPaddingInline;const styles$1=aphrodite.StyleSheet.create({container:{alignItems:"center",flexDirection:"row",justifyContent:"stretch"},icon:{pointerEvents:"none",position:"absolute",insetInlineEnd:fieldPaddingInline},textField:{width:"100%",paddingInlineStart:fieldPaddingInline,paddingInlineEnd:fieldPaddingInlineEnd}});
47
63
 
48
64
  function FocusManager(props){const{children,referenceElement,onStartFocused,onEndFocused}=props;const rootNodeRef=React__namespace.useRef(null);const focusableElementsRef=React__namespace.useRef([]);const focusableElementsInsideRef=React__namespace.useRef([]);const nextFocusableElementRef=React__namespace.useRef(null);const getFocusableElements=React__namespace.useCallback(()=>{return wonderBlocksCore.findFocusableNodes(document)},[]);const getReferenceIndex=React__namespace.useCallback(()=>{if(!referenceElement){return -1}return focusableElementsRef.current.indexOf(referenceElement)},[referenceElement]);const getNextFocusableElement=React__namespace.useCallback(()=>{const referenceIndex=getReferenceIndex();if(referenceIndex>=0){const nextElementIndex=referenceIndex<focusableElementsRef.current.length-1?referenceIndex+1:0;return focusableElementsRef.current[nextElementIndex]}return undefined},[getReferenceIndex]);React__namespace.useEffect(()=>{focusableElementsRef.current=getFocusableElements();nextFocusableElementRef.current=getNextFocusableElement();const handleKeydownReferenceElement=e=>{if(e.key==="Tab"&&!e.shiftKey){if(rootNodeRef.current){focusableElementsInsideRef.current=wonderBlocksCore.findFocusableNodes(rootNodeRef.current);}if(focusableElementsInsideRef.current.length>0){e.preventDefault();focusableElementsInsideRef.current[0]?.focus();}}};const handleKeydownNextFocusableElement=e=>{if(e.key==="Tab"&&e.shiftKey){if(rootNodeRef.current){focusableElementsInsideRef.current=wonderBlocksCore.findFocusableNodes(rootNodeRef.current);}if(focusableElementsInsideRef.current.length>0){e.preventDefault();const lastIndex=focusableElementsInsideRef.current.length-1;focusableElementsInsideRef.current[lastIndex]?.focus();}}};if(referenceElement){referenceElement.addEventListener("keydown",handleKeydownReferenceElement,true);}if(nextFocusableElementRef.current){nextFocusableElementRef.current.addEventListener("keydown",handleKeydownNextFocusableElement,true);}return ()=>{if(referenceElement){referenceElement.removeEventListener("keydown",handleKeydownReferenceElement,true);}if(nextFocusableElementRef.current){nextFocusableElementRef.current.removeEventListener("keydown",handleKeydownNextFocusableElement,true);}}},[referenceElement,getNextFocusableElement,getFocusableElements]);const setComponentRootNode=React__namespace.useCallback(node=>{if(!node){return}rootNodeRef.current=node;focusableElementsInsideRef.current=wonderBlocksCore.findFocusableNodes(node);},[]);const handleFocusPreviousFocusableElement=React__namespace.useCallback(()=>{if(referenceElement){referenceElement.focus();}if(onStartFocused){onStartFocused();}},[referenceElement,onStartFocused]);const handleFocusNextFocusableElement=React__namespace.useCallback(()=>{if(nextFocusableElementRef.current){nextFocusableElementRef.current.focus();}if(onEndFocused){onEndFocused();}},[onEndFocused]);return jsxRuntime.jsxs(React__namespace.Fragment,{children:[jsxRuntime.jsx("div",{tabIndex:0,"data-testid":"focus-sentinel-prev",onFocus:handleFocusPreviousFocusableElement,style:{position:"fixed"}}),jsxRuntime.jsx("div",{"data-testid":"date-picker-overlay",ref:setComponentRootNode,children:children}),jsxRuntime.jsx("div",{tabIndex:0,"data-testid":"focus-sentinel-next",onFocus:handleFocusNextFocusableElement,style:{position:"fixed"}})]})}
49
65
 
50
- const DEFAULT_STYLE={background:wonderBlocksTokens.semanticColor.core.background.base.default,borderRadius:wonderBlocksTokens.border.radius.radius_040,border:`solid ${wonderBlocksTokens.border.width.thin} ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,boxShadow:wonderBlocksTokens.boxShadow.mid};const BASE_CONTAINER_STYLES={fontFamily:wonderBlocksTokens.font.family.sans,padding:wonderBlocksTokens.sizing.size_100};const OUT_OF_BOUNDARIES_STYLES={visibility:"hidden"};const DatePickerOverlay=({children,referenceElement,onClose,style=DEFAULT_STYLE})=>{if(!referenceElement){return null}const modalHost=wonderBlocksModal.maybeGetPortalMountedModalHostElement(referenceElement)||document.querySelector("body");if(!modalHost){return null}return reactDom.createPortal(jsxRuntime.jsx(FocusManager,{referenceElement:referenceElement,onEndFocused:onClose,children:jsxRuntime.jsx(reactPopper.Popper,{referenceElement:referenceElement,placement:"bottom-start",strategy:"fixed",modifiers:[{name:"preventOverflow",options:{rootBoundary:"viewport"}}],children:({placement,ref,style:popperStyle,isReferenceHidden,hasPopperEscaped})=>{const isTestEnvironment=typeof window!=="undefined"&&window.navigator.userAgent.includes("jsdom");const outOfBoundaries=!isTestEnvironment&&(isReferenceHidden||hasPopperEscaped);const combinedStyles={...BASE_CONTAINER_STYLES,...popperStyle,...style,...outOfBoundaries&&OUT_OF_BOUNDARIES_STYLES};return jsxRuntime.jsx("div",{ref:ref,style:combinedStyles,"data-placement":placement,children:children})}})}),modalHost)};
66
+ const DEFAULT_STYLE={background:wonderBlocksTokens.semanticColor.core.background.base.default,borderRadius:wonderBlocksTokens.border.radius.radius_040,border:`solid ${wonderBlocksTokens.border.width.thin} ${wonderBlocksTokens.semanticColor.core.border.neutral.subtle}`,boxShadow:wonderBlocksTokens.boxShadow.mid};const BASE_CONTAINER_STYLES={fontFamily:wonderBlocksTokens.font.family.sans,padding:wonderBlocksTokens.sizing.size_100};const OUT_OF_BOUNDARIES_STYLES={visibility:"hidden"};const DatePickerOverlay=({children,referenceElement,onClose,dir="ltr",style=DEFAULT_STYLE})=>{if(!referenceElement){return null}const placement=dir==="rtl"?"bottom-end":"bottom-start";const modalHost=wonderBlocksModal.maybeGetPortalMountedModalHostElement(referenceElement)||document.querySelector("body");if(!modalHost){return null}return reactDom.createPortal(jsxRuntime.jsx(FocusManager,{referenceElement:referenceElement,onEndFocused:onClose,children:jsxRuntime.jsx(reactPopper.Popper,{referenceElement:referenceElement,placement:placement,strategy:"fixed",modifiers:[{name:"preventOverflow",options:{rootBoundary:"viewport"}}],children:({placement,ref,style:popperStyle,isReferenceHidden,hasPopperEscaped})=>{const isTestEnvironment=typeof window!=="undefined"&&window.navigator.userAgent.includes("jsdom");const outOfBoundaries=!isTestEnvironment&&(isReferenceHidden||hasPopperEscaped);const combinedStyles={...BASE_CONTAINER_STYLES,...popperStyle,...style,...outOfBoundaries&&OUT_OF_BOUNDARIES_STYLES};return jsxRuntime.jsx("div",{ref:ref,style:combinedStyles,"data-placement":placement,children:children})}})}),modalHost)};
51
67
 
52
- const customRootStyle={"--rdp-accent-color":wonderBlocksTokens.semanticColor.core.border.instructive.default};const DatePicker=props=>{const{locale: locale$1,updateDate,dateFormat,disabled,id,maxDate,minDate,inputAriaLabel,placeholder,selectedDate,style,closeOnSelect=true,resetInvalidValueOnBlur=true,footer}=props;const[showOverlay,setShowOverlay]=React__namespace.useState(false);const[currentDate,setCurrentDate]=React__namespace.useState(selectedDate);const[displayMonth,setDisplayMonth]=React__namespace.useState(selectedDate?TemporalLocaleUtils.temporalDateToJsDate(selectedDate):undefined);const datePickerInputRef=React__namespace.useRef(null);const datePickerRef=React__namespace.useRef(null);const refWrapper=React__namespace.useRef(null);const open=React__namespace.useCallback(()=>{if(!disabled){setShowOverlay(true);}},[disabled]);const close=React__namespace.useCallback(()=>{setShowOverlay(false);datePickerInputRef.current?.validateInput?.();},[]);const computedLocale=locale$1??locale.enUS;const dir=refWrapper.current?.closest("[dir]")?.getAttribute("dir")||"ltr";React__namespace.useEffect(()=>{setCurrentDate(selectedDate);if(selectedDate){setDisplayMonth(TemporalLocaleUtils.temporalDateToJsDate(selectedDate));}},[selectedDate]);React__namespace.useEffect(()=>{const handleClick=e=>{const target=e.target;const thisElement=refWrapper.current;const dayPickerCalendar=datePickerRef.current;const isElement=target instanceof Element;const inThisElement=isElement&&thisElement?.contains(target);const inCalendar=isElement&&dayPickerCalendar?.contains(target);const inPortal=isElement&&target.closest("[data-placement]")!==null;const shouldClose=showOverlay&&closeOnSelect&&thisElement&&!inThisElement&&!inCalendar&&!inPortal;if(shouldClose){setShowOverlay(false);}};document.addEventListener("mouseup",handleClick);return ()=>{document.removeEventListener("mouseup",handleClick);}},[showOverlay,closeOnSelect]);const isLeavingDropdown=e=>{const dayPickerCalendar=datePickerRef.current;if(!dayPickerCalendar){return true}if(e.relatedTarget instanceof Node){return !dayPickerCalendar.contains(e.relatedTarget)}return true};const handleInputBlur=e=>{if(isLeavingDropdown(e)){close();}};const handleInputChange=(selectedDate,modifiers)=>{if(!selectedDate){setCurrentDate(null);updateDate(null);return}const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(selectedDate);const isDisabled=typeof modifiers.disabled==="function"?modifiers.disabled(selectedDate):modifiers.disabled;if(isDisabled){updateDate(wrappedDate);return}setCurrentDate(wrappedDate);setDisplayMonth(selectedDate);updateDate(wrappedDate);};const handleKeyDown=e=>{if(e.key==="Escape"){close();datePickerInputRef.current?.focus();}if(e.key==="ArrowDown"&&!showOverlay){e.preventDefault();open();}if(e.key==="Enter"){e.preventDefault();if(showOverlay){if(closeOnSelect){close();}}else {open();}}};const RootWithEsc=props=>{const{onKeyDown,rootRef:_,...rest}=props;return jsxRuntime.jsx("div",{...rest,tabIndex:-1,onKeyDown:e=>{onKeyDown?.(e);if(e.key==="Escape"){close();datePickerInputRef.current?.focus();}}})};const handleDayClick=(date,{disabled})=>{if(disabled||!date){return}datePickerInputRef.current?.focus();const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(date);setCurrentDate(wrappedDate);setDisplayMonth(date);updateDate(wrappedDate);setShowOverlay(!closeOnSelect);};const renderInput=modifiers=>{const selectedDateAsValue=currentDate?TemporalLocaleUtils.formatDate(currentDate,dateFormat,computedLocale):"";return jsxRuntime.jsx(DatePickerInput,{onBlur:handleInputBlur,onFocus:open,onClick:open,onChange:handleInputChange,onKeyDown:handleKeyDown,"aria-label":inputAriaLabel,disabled:disabled,id:id,placeholder:placeholder,value:selectedDateAsValue,ref:datePickerInputRef,dateFormat:dateFormat,locale:computedLocale.code,parseDate:TemporalLocaleUtils.parseDateToJsDate,getModifiersForDay:TemporalLocaleUtils.getModifiersForDay,modifiers:modifiers,resetInvalidValueOnBlur:resetInvalidValueOnBlur,testId:id&&`${id}-input`})};const maybeRenderFooter=()=>{if(!footer){return null}return jsxRuntime.jsx(wonderBlocksCore.View,{testId:"date-picker-footer",style:styles.footer,children:footer({close})})};const selectedDateValue=currentDate?TemporalLocaleUtils.temporalDateToJsDate(currentDate):undefined;const minDateToShow=minDate&&selectedDateValue?temporalPolyfill.Temporal.PlainDate.compare(minDate,currentDate)<0?TemporalLocaleUtils.temporalDateToJsDate(minDate):selectedDateValue:minDate?TemporalLocaleUtils.temporalDateToJsDate(minDate):undefined;const modifiers={selected:selectedDateValue,disabled:date=>{const temporalDate=TemporalLocaleUtils.jsDateToTemporalDate(date);return minDate&&temporalPolyfill.Temporal.PlainDate.compare(temporalDate,minDate)<0||maxDate&&temporalPolyfill.Temporal.PlainDate.compare(temporalDate,maxDate)>0||false}};return jsxRuntime.jsxs(wonderBlocksCore.View,{style:[styles.wrapper,style],ref:refWrapper,children:[renderInput(modifiers),showOverlay&&jsxRuntime.jsx(DatePickerOverlay,{referenceElement:datePickerInputRef.current,onClose:close,children:jsxRuntime.jsxs(wonderBlocksCore.View,{ref:datePickerRef,children:[jsxRuntime.jsx(reactDayPicker.DayPicker,{mode:"single",selected:selectedDateValue,month:displayMonth,onMonthChange:setDisplayMonth,startMonth:minDateToShow??undefined,endMonth:maxDate?TemporalLocaleUtils.temporalDateToJsDate(maxDate):undefined,modifiers:modifiers,onDayClick:handleDayClick,components:{Root:RootWithEsc},locale:computedLocale,dir:dir,styles:{root:{...customRootStyle},nav:{width:"auto"}}}),maybeRenderFooter()]})})]})};DatePicker.defaultProps={closeOnSelect:true};const styles=aphrodite.StyleSheet.create({wrapper:{width:225,height:40},footer:{margin:wonderBlocksTokens.sizing.size_120,marginBlockStart:0}});
68
+ const customRootStyle={"--rdp-accent-color":wonderBlocksTokens.semanticColor.core.border.instructive.default};const DatePicker=props=>{const{locale: locale$1,updateDate,dateFormat,disabled,id,maxDate,minDate,inputAriaLabel,placeholder,selectedDate,style,closeOnSelect=true,resetInvalidValueOnBlur=true,footer}=props;const[showOverlay,setShowOverlay]=React__namespace.useState(false);const[currentDate,setCurrentDate]=React__namespace.useState(selectedDate);const datePickerInputRef=React__namespace.useRef(null);const datePickerRef=React__namespace.useRef(null);const refWrapper=React__namespace.useRef(null);const skipNextOpenRef=React__namespace.useRef(false);const{handleEscapeKeyDown}=useEscapeKeyupCapture();const{displayMonth,setDisplayMonth,displayMonthRef,inputDrivenMonthRef,setDisplayMonthAndRefs}=useDisplayMonth({selectedDate});const open=React__namespace.useCallback(()=>{if(skipNextOpenRef.current){skipNextOpenRef.current=false;return}if(!disabled){if(selectedDate!=null){const jsDate=TemporalLocaleUtils.temporalDateToJsDate(selectedDate);setDisplayMonthAndRefs(jsDate);}else {displayMonthRef.current=displayMonthRef.current??displayMonth;}setShowOverlay(true);}},[disabled,displayMonth,displayMonthRef,selectedDate,setDisplayMonthAndRefs,skipNextOpenRef]);const{handleInputChange,clearInputDrivenMonth}=useOverlayMonthFromInput({inputDrivenMonthRef,setDisplayMonth,setDisplayMonthAndRefs,setCurrentDate,updateDate,dateFormat,localeCode:locale$1?.code});const close=React__namespace.useCallback(()=>{clearInputDrivenMonth();if(selectedDate!=null){const jsDate=TemporalLocaleUtils.temporalDateToJsDate(selectedDate);setDisplayMonthAndRefs(jsDate);}else {setDisplayMonthAndRefs(null);}setShowOverlay(false);datePickerInputRef.current?.validateInput?.();},[selectedDate,setDisplayMonthAndRefs,clearInputDrivenMonth,datePickerInputRef]);useCloseOnOutsideClick({refWrapper,datePickerRef,showOverlay,closeOnSelect,close});useSelectedDateSync({selectedDate,setCurrentDate,setDisplayMonthAndRefs});const computedLocale=locale$1??locale.enUS;const selectedDateValue=currentDate?TemporalLocaleUtils.temporalDateToJsDate(currentDate):undefined;const modifiers=useDatePickerModifiers({selectedDateValue,minDate,maxDate});const formatDateForInput=useFormatDateForInput({dateFormat,locale:computedLocale});const dir=refWrapper.current?.closest("[dir]")?.getAttribute("dir")||"ltr";const handleMonthChange=React__namespace.useCallback(newMonth=>{clearInputDrivenMonth();setDisplayMonthAndRefs(newMonth);},[clearInputDrivenMonth,setDisplayMonthAndRefs]);const isLeavingDropdown=e=>{const dayPickerCalendar=datePickerRef.current;if(!dayPickerCalendar){return true}if(e.relatedTarget instanceof Node){return !dayPickerCalendar.contains(e.relatedTarget)}return true};const handleInputBlur=e=>{if(isLeavingDropdown(e)){close();}};const onEscapeCloseOverlay=React__namespace.useCallback(()=>{skipNextOpenRef.current=true;close();datePickerInputRef.current?.focus();},[close,skipNextOpenRef,datePickerInputRef]);const handleKeyDown=e=>{if(e.key==="Escape"){if(showOverlay){handleEscapeKeyDown(e,onEscapeCloseOverlay);}}if(e.key==="ArrowDown"&&!showOverlay){e.preventDefault();skipNextOpenRef.current=false;open();}if(e.key==="Enter"){e.preventDefault();if(showOverlay){if(closeOnSelect){close();}}else {skipNextOpenRef.current=false;open();}}};const RootWithEsc=React__namespace.useCallback(props=>{const{onKeyDown,rootRef:_,...rest}=props;return jsxRuntime.jsx("div",{...rest,tabIndex:-1,onKeyDown:e=>{onKeyDown?.(e);if(e.key==="Escape"){handleEscapeKeyDown(e,onEscapeCloseOverlay);}}})},[handleEscapeKeyDown,onEscapeCloseOverlay]);const dayPickerComponents=React__namespace.useMemo(()=>({Root:RootWithEsc}),[RootWithEsc]);const handleDayClick=React__namespace.useCallback((date,{disabled})=>{if(disabled||!date){return}datePickerInputRef.current?.focus();const wrappedDate=TemporalLocaleUtils.jsDateToTemporalDate(date);setCurrentDate(wrappedDate);const monthDate=new Date(date);clearInputDrivenMonth();setDisplayMonthAndRefs(monthDate);updateDate(wrappedDate);setShowOverlay(!closeOnSelect);},[updateDate,closeOnSelect,setDisplayMonthAndRefs,datePickerInputRef,clearInputDrivenMonth]);const renderInput=inputModifiers=>{const selectedDateAsValue=formatDateForInput(currentDate);return jsxRuntime.jsx(DatePickerInput,{onBlur:handleInputBlur,onFocus:open,onClick:open,onChange:handleInputChange,onKeyDown:handleKeyDown,"aria-label":inputAriaLabel,disabled:disabled,id:id,placeholder:placeholder,value:selectedDateAsValue,ref:datePickerInputRef,dateFormat:dateFormat,locale:computedLocale.code,parseDate:TemporalLocaleUtils.parseDateToJsDate,getModifiersForDay:TemporalLocaleUtils.getModifiersForDay,modifiers:inputModifiers,resetInvalidValueOnBlur:resetInvalidValueOnBlur,testId:id&&`${id}-input`})};const maybeRenderFooter=()=>{if(!footer){return null}return jsxRuntime.jsx(wonderBlocksCore.View,{testId:"date-picker-footer",style:styles.footer,children:footer({close})})};const minDateToShow=minDate&&selectedDateValue?temporalPolyfill.Temporal.PlainDate.compare(minDate,currentDate)<0?TemporalLocaleUtils.temporalDateToJsDate(minDate):selectedDateValue:minDate?TemporalLocaleUtils.temporalDateToJsDate(minDate):undefined;const dayPickerEndMonth=React__namespace.useMemo(()=>maxDate?TemporalLocaleUtils.temporalDateToJsDate(maxDate):undefined,[maxDate]);const dayPickerStyles=React__namespace.useMemo(()=>({root:{...customRootStyle},nav:{width:"auto"}}),[]);const inputDrivenMonth=inputDrivenMonthRef.current;const isInputDriven=inputDrivenMonth!=null;const selectedDateAsJs=selectedDate!=null?TemporalLocaleUtils.temporalDateToJsDate(selectedDate):undefined;const baseMonth=displayMonthRef.current??(showOverlay&&selectedDateAsJs?selectedDateAsJs:undefined)??displayMonth??selectedDateValue??new Date;const firstOfBaseMonth=new Date(baseMonth.getFullYear(),baseMonth.getMonth(),1);const pickerKey=isInputDriven?`input-${inputDrivenMonth.getTime()}`:`picker-${baseMonth.getTime()}`;const inputDrivenMonthMs=inputDrivenMonth?.getTime();const firstOfBaseMonthMs=firstOfBaseMonth.getTime();const dayPickerMonthProps=React__namespace.useMemo(()=>{if(isInputDriven&&inputDrivenMonthMs!=null){const d=new Date(inputDrivenMonthMs);return {month:new Date(d.getFullYear(),d.getMonth(),1),onMonthChange:handleMonthChange}}return {defaultMonth:new Date(firstOfBaseMonthMs)}},[isInputDriven,inputDrivenMonthMs,firstOfBaseMonthMs,handleMonthChange]);return jsxRuntime.jsxs(wonderBlocksCore.View,{style:style,ref:refWrapper,children:[renderInput(modifiers),showOverlay&&jsxRuntime.jsx(DatePickerOverlay,{referenceElement:datePickerInputRef.current,onClose:close,dir:dir==="rtl"?"rtl":"ltr",children:jsxRuntime.jsxs(wonderBlocksCore.View,{ref:datePickerRef,children:[jsxRuntime.jsx(reactDayPicker.DayPicker,{mode:"single",selected:selectedDateValue,...dayPickerMonthProps,startMonth:minDateToShow??undefined,endMonth:dayPickerEndMonth,modifiers:modifiers,onDayClick:handleDayClick,components:dayPickerComponents,locale:computedLocale,dir:dir,styles:dayPickerStyles},pickerKey),maybeRenderFooter()]})})]})};DatePicker.defaultProps={closeOnSelect:true};const styles=aphrodite.StyleSheet.create({footer:{margin:wonderBlocksTokens.sizing.size_120,marginBlockStart:0}});
53
69
 
54
70
  exports.DatePicker = DatePicker;
55
71
  exports.TemporalLocaleUtils = TemporalLocaleUtils;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Returns true when the user has finished typing a full date in a text format
3
+ * (LL, MMMM D YYYY, MMM D YYYY): reparsed date matches, and normalized input
4
+ * matches the formatted date.
5
+ */
6
+ export declare function isTextFormatCommitComplete(inputValue: string, dateFromInput: Date, dateFormat: string | null | undefined, localeCode?: string | null): boolean;
@@ -2,6 +2,18 @@ import { Temporal } from "temporal-polyfill";
2
2
  import type { Locale } from "react-day-picker/locale";
3
3
  import { CustomModifiers } from "./types";
4
4
  export declare const enUSLocaleCode = "en-US";
5
+ /**
6
+ * True if the format displays the month as text (LL, MMMM D YYYY, MMM D YYYY).
7
+ * Used to decide when to treat input as "complete" vs partial and when to sync overlay month from typing.
8
+ */
9
+ export declare function isTextFormatDate(formatString: string | null | undefined): boolean;
10
+ /**
11
+ * Normalize a date string for comparison (e.g. round-trip or commit checks).
12
+ * Trims, lowercases, collapses whitespace, and replaces common punctuation
13
+ * (comma, period, narrow no-break space) with space so minor formatting
14
+ * differences don't invalidate the input.
15
+ */
16
+ export declare function normalizeDateStringForComparison(s: string): string;
5
17
  /**
6
18
  * Utility functions for working with Temporal dates in react-day-picker.
7
19
  * Uses Intl.DateTimeFormat for locale-aware date formatting and parsing.
@@ -49,12 +61,11 @@ export declare const enUSLocaleCode = "en-US";
49
61
  * automatically falls back to ISO 8601 format and logs a warning to the console.
50
62
  * This ensures the function never throws errors and always returns a valid date string.
51
63
  */
52
- export declare function formatDate(date: Temporal.PlainDate, format: string | Array<string> | null | undefined, locale?: Locale | string): string;
64
+ export declare function formatDate(date: Temporal.PlainDate, formatString: string | null | undefined, locale?: Locale | string): string;
53
65
  /**
54
66
  * Parse a date string into a Temporal.PlainDate.
55
- * Attempts multiple formats if an array is provided.
56
67
  */
57
- export declare function parseDate(str: string, format: string | Array<string> | null | undefined, locale?: string): Temporal.PlainDate | undefined;
68
+ export declare function parseDate(str: string, formatString: string | null | undefined, locale?: string): Temporal.PlainDate | undefined;
58
69
  export declare const getModifiersForDay: (day: Date, modifiers: Partial<CustomModifiers>) => Array<string>;
59
70
  /**
60
71
  * Convert a Temporal.PlainDate to a JavaScript Date object.
@@ -79,7 +90,7 @@ export declare function jsDateToTemporalDate(date: Date): Temporal.PlainDate;
79
90
  * parseDateToJsDate("1/28", "MM/DD/YYYY") // ✗ Returns undefined (incomplete)
80
91
  * parseDateToJsDate("2026-01-28", "MM/DD/YYYY") // ✗ Returns undefined (wrong format)
81
92
  */
82
- export declare function parseDateToJsDate(value: string | Date, format: string | Array<string> | null | undefined, locale?: string | null | undefined): Date | null | undefined;
93
+ export declare function parseDateToJsDate(value: string | Date, formatString: string | null | undefined, locale?: string | null | undefined): Date | null | undefined;
83
94
  /**
84
95
  * Get the start of the ISO week (Monday) for a given date.
85
96
  * ISO weeks start on Monday (dayOfWeek = 1) and end on Sunday (dayOfWeek = 7).
@@ -105,6 +116,8 @@ export declare const endOfDay: (date: Date) => Date;
105
116
  */
106
117
  export declare const TemporalLocaleUtils: {
107
118
  formatDate: typeof formatDate;
119
+ isTextFormatDate: typeof isTextFormatDate;
120
+ normalizeDateStringForComparison: typeof normalizeDateStringForComparison;
108
121
  parseDate: typeof parseDate;
109
122
  parseDateToJsDate: typeof parseDateToJsDate;
110
123
  startOfIsoWeek: (date: Temporal.PlainDate) => Temporal.PlainDate;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Date picker component for Wonder Blocks.",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "0.1.2",
6
+ "version": "1.0.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -29,16 +29,17 @@
29
29
  "dependencies": {
30
30
  "react-day-picker": "^9.11.1",
31
31
  "@khanacademy/wonder-blocks-core": "12.4.3",
32
+ "@khanacademy/wonder-blocks-form": "7.5.4",
32
33
  "@khanacademy/wonder-blocks-icon": "5.3.7",
33
- "@khanacademy/wonder-blocks-form": "7.5.3",
34
- "@khanacademy/wonder-blocks-modal": "8.5.14",
35
- "@khanacademy/wonder-blocks-tokens": "15.0.0",
36
- "@khanacademy/wonder-blocks-styles": "0.2.38"
34
+ "@khanacademy/wonder-blocks-modal": "8.5.15",
35
+ "@khanacademy/wonder-blocks-styles": "0.2.38",
36
+ "@khanacademy/wonder-blocks-tokens": "15.0.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@phosphor-icons/core": "^2.0.2",
40
40
  "@popperjs/core": "^2.10.1",
41
41
  "aphrodite": "^1.2.5",
42
+ "date-fns": "^4.1.0",
42
43
  "react": "18.2.0",
43
44
  "react-dom": "18.2.0",
44
45
  "react-popper": "^2.3.0",