UNPKG

@zag-js/date-picker

Version:

Core logic for the date-picker widget implemented as a state machine

1,200 lines (1,198 loc) • 44.8 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/date-picker.machine.ts var date_picker_machine_exports = {}; __export(date_picker_machine_exports, { machine: () => machine }); module.exports = __toCommonJS(date_picker_machine_exports); var import_date = require("@internationalized/date"); var import_core = require("@zag-js/core"); var import_date_utils = require("@zag-js/date-utils"); var import_dismissable = require("@zag-js/dismissable"); var import_dom_query = require("@zag-js/dom-query"); var import_live_region = require("@zag-js/live-region"); var import_popper = require("@zag-js/popper"); var dom = __toESM(require("./date-picker.dom.js")); var import_date_picker = require("./date-picker.utils.js"); var { and } = (0, import_core.createGuards)(); function isDateArrayEqual(a, b) { if (a?.length !== b?.length) return false; const len = Math.max(a.length, b.length); for (let i = 0; i < len; i++) { if (!(0, import_date_utils.isDateEqual)(a[i], b[i])) return false; } return true; } function getValueAsString(value, prop) { return value.map((date) => { if (date == null) return ""; return prop("format")(date, { locale: prop("locale"), timeZone: prop("timeZone") }); }); } var machine = (0, import_core.createMachine)({ props({ props }) { const locale = props.locale || "en-US"; const timeZone = props.timeZone || "UTC"; const selectionMode = props.selectionMode || "single"; const numOfMonths = props.numOfMonths || 1; let calendar; if (props.createCalendar) { const resolved = new Intl.DateTimeFormat(locale).resolvedOptions(); const calendarId = resolved.calendar; if (calendarId !== "gregory" && calendarId !== "iso8601") { calendar = props.createCalendar(calendarId); } } const toTargetCalendar = (date) => { if (!calendar) return date; if (date.calendar.identifier === calendar.identifier) return date; return (0, import_date.toCalendar)(date, calendar); }; const defaultValue = props.defaultValue ? (0, import_date_picker.sortDates)(props.defaultValue).map((date) => (0, import_date_utils.constrainValue)(toTargetCalendar(date), props.min, props.max)) : void 0; const value = props.value ? (0, import_date_picker.sortDates)(props.value).map((date) => (0, import_date_utils.constrainValue)(toTargetCalendar(date), props.min, props.max)) : void 0; let focusedValue = props.focusedValue || props.defaultFocusedValue || value?.[0] || defaultValue?.[0] || (0, import_date_utils.getTodayDate)(timeZone, calendar); focusedValue = (0, import_date_utils.constrainValue)(toTargetCalendar(focusedValue), props.min, props.max); const minView = "day"; const maxView = "year"; const defaultView = (0, import_date_picker.clampView)(props.view || minView, minView, maxView); return { locale, numOfMonths, timeZone, selectionMode, defaultView, minView, maxView, outsideDaySelectable: false, closeOnSelect: true, format(date, { locale: locale2, timeZone: timeZone2 }) { const formatter = new import_date.DateFormatter(locale2, { timeZone: timeZone2, day: "2-digit", month: "2-digit", year: "numeric", calendar: calendar?.identifier }); return formatter.format(date.toDate(timeZone2)); }, parse(value2, { locale: locale2, timeZone: timeZone2 }) { return (0, import_date_utils.parseDateString)(value2, locale2, timeZone2); }, ...props, focusedValue: typeof props.focusedValue === "undefined" ? void 0 : focusedValue, defaultFocusedValue: focusedValue, value, defaultValue: defaultValue ?? [], positioning: { placement: "bottom", ...props.positioning } }; }, initialState({ prop }) { const open = prop("open") || prop("defaultOpen") || prop("inline"); return open ? "open" : "idle"; }, refs() { return { announcer: void 0 }; }, context({ prop, bindable, getContext }) { return { focusedValue: bindable(() => ({ defaultValue: prop("defaultFocusedValue"), value: prop("focusedValue"), isEqual: import_date_utils.isDateEqual, hash: (v) => v.toString(), sync: true, onChange(focusedValue) { const context = getContext(); const view = context.get("view"); const value = context.get("value"); const valueAsString = getValueAsString(value, prop); prop("onFocusChange")?.({ value, valueAsString, view, focusedValue }); } })), value: bindable(() => ({ defaultValue: prop("defaultValue"), value: prop("value"), isEqual: isDateArrayEqual, hash: (v) => v.map((date) => date?.toString() ?? "").join(","), onChange(value) { const context = getContext(); const valueAsString = getValueAsString(value, prop); prop("onValueChange")?.({ value, valueAsString, view: context.get("view") }); } })), inputValue: bindable(() => ({ defaultValue: "" })), activeIndex: bindable(() => ({ defaultValue: 0, sync: true })), hoveredValue: bindable(() => ({ defaultValue: null, isEqual: import_date_utils.isDateEqual })), view: bindable(() => ({ defaultValue: prop("defaultView"), value: prop("view"), onChange(value) { prop("onViewChange")?.({ view: value }); } })), startValue: bindable(() => { const focusedValue = prop("focusedValue") || prop("defaultFocusedValue"); return { defaultValue: (0, import_date_utils.alignDate)(focusedValue, "start", { months: prop("numOfMonths") }, prop("locale")), isEqual: import_date_utils.isDateEqual, hash: (v) => v.toString() }; }), currentPlacement: bindable(() => ({ defaultValue: void 0 })), restoreFocus: bindable(() => ({ defaultValue: false })) }; }, computed: { isInteractive: ({ prop }) => !prop("disabled") && !prop("readOnly"), visibleDuration: ({ prop }) => ({ months: prop("numOfMonths") }), endValue: ({ context, computed }) => (0, import_date_utils.getEndDate)(context.get("startValue"), computed("visibleDuration")), visibleRange: ({ context, computed }) => ({ start: context.get("startValue"), end: computed("endValue") }), visibleRangeText: ({ context, prop, computed }) => (0, import_date_picker.getVisibleRangeText)({ view: context.get("view"), startValue: context.get("startValue"), endValue: computed("endValue"), locale: prop("locale"), timeZone: prop("timeZone"), selectionMode: prop("selectionMode") }), isPrevVisibleRangeValid: ({ context, prop }) => !(0, import_date_utils.isPreviousRangeInvalid)(context.get("startValue"), prop("min"), prop("max")), isNextVisibleRangeValid: ({ prop, computed }) => !(0, import_date_utils.isNextRangeInvalid)(computed("endValue"), prop("min"), prop("max")), valueAsString: ({ context, prop }) => getValueAsString(context.get("value"), prop) }, effects: ["setupLiveRegion"], watch({ track, prop, context, action, computed }) { track([() => prop("locale")], () => { action(["setStartValue", "syncInputElement"]); }); track([() => context.hash("focusedValue")], () => { action(["setStartValue", "focusActiveCellIfNeeded", "setHoveredValueIfKeyboard"]); }); track([() => context.hash("startValue")], () => { action(["syncMonthSelectElement", "syncYearSelectElement", "invokeOnVisibleRangeChange"]); }); track([() => context.get("inputValue")], () => { action(["syncInputValue"]); }); track([() => context.hash("value")], () => { action(["syncInputElement"]); }); track([() => computed("valueAsString").toString()], () => { action(["announceValueText"]); }); track([() => context.get("view")], () => { action(["focusActiveCell"]); }); track([() => prop("open")], () => { action(["toggleVisibility"]); }); }, on: { "VALUE.SET": { actions: ["setDateValue", "setFocusedDate"] }, "VIEW.SET": { actions: ["setView"] }, "FOCUS.SET": { actions: ["setFocusedDate"] }, "VALUE.CLEAR": { actions: [ "clearDateValue", "clearFocusedDate", "setActiveIndexToStart", "clearHoveredDate", "focusFirstInputElement" ] }, "INPUT.CHANGE": [ { guard: "isInputValueEmpty", actions: ["setInputValue", "clearDateValue", "clearFocusedDate"] }, { actions: ["setInputValue", "focusParsedDate"] } ], "INPUT.ENTER": { actions: ["focusParsedDate", "selectFocusedDate"] }, "INPUT.FOCUS": { actions: ["setActiveIndex"] }, "INPUT.BLUR": [ { guard: "shouldFixOnBlur", actions: ["setActiveIndexToStart", "selectParsedDate"] }, { actions: ["setActiveIndexToStart"] } ], "PRESET.CLICK": [ { guard: "isOpenControlled", actions: ["setDateValue", "setFocusedDate", "invokeOnClose"] }, { target: "focused", actions: ["setDateValue", "setFocusedDate", "focusInputElement"] } ], "GOTO.NEXT": [ { guard: "isYearView", actions: ["focusNextDecade", "announceVisibleRange"] }, { guard: "isMonthView", actions: ["focusNextYear", "announceVisibleRange"] }, { actions: ["focusNextPage"] } ], "GOTO.PREV": [ { guard: "isYearView", actions: ["focusPreviousDecade", "announceVisibleRange"] }, { guard: "isMonthView", actions: ["focusPreviousYear", "announceVisibleRange"] }, { actions: ["focusPreviousPage"] } ] }, states: { idle: { tags: ["closed"], on: { "CONTROLLED.OPEN": { target: "open", actions: ["focusFirstSelectedDate", "focusActiveCell"] }, "TRIGGER.CLICK": [ { guard: "isOpenControlled", actions: ["invokeOnOpen"] }, { target: "open", actions: ["focusFirstSelectedDate", "focusActiveCell", "invokeOnOpen"] } ], OPEN: [ { guard: "isOpenControlled", actions: ["invokeOnOpen"] }, { target: "open", actions: ["focusFirstSelectedDate", "focusActiveCell", "invokeOnOpen"] } ] } }, focused: { tags: ["closed"], on: { "CONTROLLED.OPEN": { target: "open", actions: ["focusFirstSelectedDate", "focusActiveCell"] }, "TRIGGER.CLICK": [ { guard: "isOpenControlled", actions: ["invokeOnOpen"] }, { target: "open", actions: ["focusFirstSelectedDate", "focusActiveCell", "invokeOnOpen"] } ], OPEN: [ { guard: "isOpenControlled", actions: ["invokeOnOpen"] }, { target: "open", actions: ["focusFirstSelectedDate", "focusActiveCell", "invokeOnOpen"] } ] } }, open: { tags: ["open"], effects: ["trackDismissableElement", "trackPositioning"], exit: ["clearHoveredDate", "resetView"], on: { "CONTROLLED.CLOSE": [ { guard: and("shouldRestoreFocus", "isInteractOutsideEvent"), target: "focused", actions: ["focusTriggerElement"] }, { guard: "shouldRestoreFocus", target: "focused", actions: ["focusInputElement"] }, { target: "idle" } ], "CELL.CLICK": [ { guard: "isAboveMinView", actions: ["setFocusedValueForView", "setPreviousView"] }, { guard: and("isRangePicker", "hasSelectedRange"), actions: ["setActiveIndexToStart", "resetSelection", "setActiveIndexToEnd"] }, // === Grouped transitions (based on `closeOnSelect` and `isOpenControlled`) === { guard: and("isRangePicker", "isSelectingEndDate", "closeOnSelect", "isOpenControlled"), actions: [ "setFocusedDate", "setSelectedDate", "setActiveIndexToStart", "clearHoveredDate", "invokeOnClose", "setRestoreFocus" ] }, { guard: and("isRangePicker", "isSelectingEndDate", "closeOnSelect"), target: "focused", actions: [ "setFocusedDate", "setSelectedDate", "setActiveIndexToStart", "clearHoveredDate", "invokeOnClose", "focusInputElement" ] }, { guard: and("isRangePicker", "isSelectingEndDate"), actions: ["setFocusedDate", "setSelectedDate", "setActiveIndexToStart", "clearHoveredDate"] }, // === { guard: "isRangePicker", actions: ["setFocusedDate", "setSelectedDate", "setActiveIndexToEnd"] }, { guard: and("isMultiPicker", "canSelectDate"), actions: ["setFocusedDate", "toggleSelectedDate"] }, { guard: "isMultiPicker", actions: ["setFocusedDate"] }, // === Grouped transitions (based on `closeOnSelect` and `isOpenControlled`) === { guard: and("closeOnSelect", "isOpenControlled"), actions: ["setFocusedDate", "setSelectedDate", "invokeOnClose"] }, { guard: "closeOnSelect", target: "focused", actions: ["setFocusedDate", "setSelectedDate", "invokeOnClose", "focusInputElement"] }, { actions: ["setFocusedDate", "setSelectedDate"] } // === ], "CELL.POINTER_MOVE": [ { guard: and("isRangePicker", "isSelectingEndDate", "isDayPointerMoveOutsideVisibleMonth"), actions: ["setHoveredDate"] }, { guard: and("isRangePicker", "isSelectingEndDate"), actions: ["setHoveredDate", "setFocusedDate"] } ], "TABLE.POINTER_LEAVE": { guard: "isRangePicker", actions: ["clearHoveredDate"] }, "TABLE.POINTER_DOWN": { actions: ["disableTextSelection"] }, "TABLE.POINTER_UP": { actions: ["enableTextSelection"] }, "TABLE.ESCAPE": [ { guard: "isOpenControlled", actions: ["focusFirstSelectedDate", "invokeOnClose"] }, { target: "focused", actions: ["focusFirstSelectedDate", "invokeOnClose", "focusTriggerElement"] } ], "TABLE.ENTER": [ { guard: "isAboveMinView", actions: ["setPreviousView"] }, { guard: and("isRangePicker", "hasSelectedRange"), actions: ["setActiveIndexToStart", "clearDateValue", "setSelectedDate", "setActiveIndexToEnd"] }, // === Grouped transitions (based on `closeOnSelect` and `isOpenControlled`) === { guard: and("isRangePicker", "isSelectingEndDate", "closeOnSelect", "isOpenControlled"), actions: ["setSelectedDate", "setActiveIndexToStart", "clearHoveredDate", "invokeOnClose"] }, { guard: and("isRangePicker", "isSelectingEndDate", "closeOnSelect"), target: "focused", actions: [ "setSelectedDate", "setActiveIndexToStart", "clearHoveredDate", "invokeOnClose", "focusInputElement" ] }, { guard: and("isRangePicker", "isSelectingEndDate"), actions: ["setSelectedDate", "setActiveIndexToStart", "clearHoveredDate"] }, // === { guard: "isRangePicker", actions: ["setSelectedDate", "setActiveIndexToEnd", "focusNextDay"] }, { guard: and("isMultiPicker", "canSelectDate"), actions: ["toggleSelectedDate"] }, { guard: "isMultiPicker" }, // === Grouped transitions (based on `closeOnSelect` and `isOpenControlled`) === { guard: and("closeOnSelect", "isOpenControlled"), actions: ["selectFocusedDate", "invokeOnClose"] }, { guard: "closeOnSelect", target: "focused", actions: ["selectFocusedDate", "invokeOnClose", "focusInputElement"] }, { actions: ["selectFocusedDate"] } // === ], "TABLE.ARROW_RIGHT": [ { guard: "isMonthView", actions: ["focusNextMonth"] }, { guard: "isYearView", actions: ["focusNextYear"] }, { actions: ["focusNextDay", "setHoveredDate"] } ], "TABLE.ARROW_LEFT": [ { guard: "isMonthView", actions: ["focusPreviousMonth"] }, { guard: "isYearView", actions: ["focusPreviousYear"] }, { actions: ["focusPreviousDay"] } ], "TABLE.ARROW_UP": [ { guard: "isMonthView", actions: ["focusPreviousMonthColumn"] }, { guard: "isYearView", actions: ["focusPreviousYearColumn"] }, { actions: ["focusPreviousWeek"] } ], "TABLE.ARROW_DOWN": [ { guard: "isMonthView", actions: ["focusNextMonthColumn"] }, { guard: "isYearView", actions: ["focusNextYearColumn"] }, { actions: ["focusNextWeek"] } ], "TABLE.PAGE_UP": { actions: ["focusPreviousSection"] }, "TABLE.PAGE_DOWN": { actions: ["focusNextSection"] }, "TABLE.HOME": [ { guard: "isMonthView", actions: ["focusFirstMonth"] }, { guard: "isYearView", actions: ["focusFirstYear"] }, { actions: ["focusSectionStart"] } ], "TABLE.END": [ { guard: "isMonthView", actions: ["focusLastMonth"] }, { guard: "isYearView", actions: ["focusLastYear"] }, { actions: ["focusSectionEnd"] } ], "TRIGGER.CLICK": [ { guard: "isOpenControlled", actions: ["invokeOnClose"] }, { target: "focused", actions: ["invokeOnClose"] } ], "VIEW.TOGGLE": { actions: ["setNextView"] }, INTERACT_OUTSIDE: [ { guard: "isOpenControlled", actions: ["setActiveIndexToStart", "invokeOnClose"] }, { guard: "shouldRestoreFocus", target: "focused", actions: ["setActiveIndexToStart", "invokeOnClose", "focusTriggerElement"] }, { target: "idle", actions: ["setActiveIndexToStart", "invokeOnClose"] } ], CLOSE: [ { guard: "isOpenControlled", actions: ["setActiveIndexToStart", "invokeOnClose"] }, { target: "idle", actions: ["setActiveIndexToStart", "invokeOnClose"] } ] } } }, implementations: { guards: { isAboveMinView: ({ context, prop }) => (0, import_date_picker.isAboveMinView)(context.get("view"), prop("minView")), isDayView: ({ context, event }) => (event.view || context.get("view")) === "day", isMonthView: ({ context, event }) => (event.view || context.get("view")) === "month", isYearView: ({ context, event }) => (event.view || context.get("view")) === "year", isRangePicker: ({ prop }) => prop("selectionMode") === "range", hasSelectedRange: ({ context }) => context.get("value").length === 2, isMultiPicker: ({ prop }) => prop("selectionMode") === "multiple", canSelectDate: ({ context, prop, event }) => { const maxSelectedDates = prop("maxSelectedDates"); if (maxSelectedDates == null) return true; const existingValues = context.get("value"); const currentValue = event.value ?? context.get("focusedValue"); const isDeselecting = existingValues.some((date) => (0, import_date_utils.isDateEqual)(date, currentValue)); if (isDeselecting) return true; return existingValues.length < maxSelectedDates; }, shouldRestoreFocus: ({ context }) => !!context.get("restoreFocus"), isSelectingEndDate: ({ context }) => context.get("activeIndex") === 1, closeOnSelect: ({ prop }) => !!prop("closeOnSelect"), isOpenControlled: ({ prop }) => prop("open") != void 0 || !!prop("inline"), isInteractOutsideEvent: ({ event }) => event.previousEvent?.type === "INTERACT_OUTSIDE", isInputValueEmpty: ({ event }) => event.value.trim() === "", shouldFixOnBlur: ({ event }) => !!event.fixOnBlur, isDayPointerMoveOutsideVisibleMonth: ({ event }) => event.cell === "day" && event.outsideRange === true }, effects: { trackPositioning({ context, prop, scope }) { if (prop("inline")) return; if (!context.get("currentPlacement")) { context.set("currentPlacement", prop("positioning").placement); } const anchorEl = dom.getControlEl(scope); const getPositionerEl2 = () => dom.getPositionerEl(scope); return (0, import_popper.getPlacement)(anchorEl, getPositionerEl2, { ...prop("positioning"), defer: true, onComplete(data) { context.set("currentPlacement", data.placement); } }); }, setupLiveRegion({ scope, refs }) { const doc = scope.getDoc(); refs.set("announcer", (0, import_live_region.createLiveRegion)({ level: "assertive", document: doc })); return () => refs.get("announcer")?.destroy?.(); }, trackDismissableElement({ scope, send, context, prop }) { if (prop("inline")) return; const getContentEl2 = () => dom.getContentEl(scope); return (0, import_dismissable.trackDismissableElement)(getContentEl2, { type: "popover", defer: true, layerStyleTargets: [() => dom.getPositionerEl(scope)], exclude: [...dom.getInputEls(scope), dom.getTriggerEl(scope), dom.getClearTriggerEl(scope)], onInteractOutside(event) { context.set("restoreFocus", !event.detail.focusable); }, onDismiss() { send({ type: "INTERACT_OUTSIDE" }); }, onEscapeKeyDown(event) { event.preventDefault(); send({ type: "TABLE.ESCAPE", src: "dismissable" }); } }); } }, actions: { setNextView({ context, prop }) { const nextView = (0, import_date_picker.getNextView)(context.get("view"), prop("minView"), prop("maxView")); context.set("view", nextView); }, setPreviousView({ context, prop }) { const prevView = (0, import_date_picker.getPreviousView)(context.get("view"), prop("minView"), prop("maxView")); context.set("view", prevView); }, setView({ context, event }) { context.set("view", event.view); }, setRestoreFocus({ context }) { context.set("restoreFocus", true); }, announceValueText({ context, prop, refs }) { const value = context.get("value"); const locale = prop("locale"); const timeZone = prop("timeZone"); let announceText; if (prop("selectionMode") === "range") { const [startDate, endDate] = value; if (startDate && endDate) { announceText = (0, import_date_utils.formatSelectedDate)(startDate, endDate, locale, timeZone); } else if (startDate) { announceText = (0, import_date_utils.formatSelectedDate)(startDate, null, locale, timeZone); } else if (endDate) { announceText = (0, import_date_utils.formatSelectedDate)(endDate, null, locale, timeZone); } else { announceText = ""; } } else { announceText = value.map((date) => (0, import_date_utils.formatSelectedDate)(date, null, locale, timeZone)).filter(Boolean).join(","); } refs.get("announcer")?.announce(announceText, 3e3); }, announceVisibleRange({ computed, refs }) { const { formatted } = computed("visibleRangeText"); refs.get("announcer")?.announce(formatted); }, disableTextSelection({ scope }) { (0, import_dom_query.disableTextSelection)({ target: dom.getContentEl(scope), doc: scope.getDoc() }); }, enableTextSelection({ scope }) { (0, import_dom_query.restoreTextSelection)({ doc: scope.getDoc(), target: dom.getContentEl(scope) }); }, focusFirstSelectedDate(params) { const { context } = params; if (!context.get("value").length) return; setFocusedValue(params, context.get("value")[0]); }, syncInputElement({ scope, computed }) { (0, import_dom_query.raf)(() => { const inputEls = dom.getInputEls(scope); inputEls.forEach((inputEl, index) => { (0, import_dom_query.setElementValue)(inputEl, computed("valueAsString")[index] || ""); }); }); }, setFocusedDate(params) { const { event } = params; const value = Array.isArray(event.value) ? event.value[0] : event.value; setFocusedValue(params, value); }, setFocusedValueForView(params) { const { context, event } = params; setFocusedValue(params, context.get("focusedValue").set({ [context.get("view")]: event.value })); }, focusNextMonth(params) { const { context } = params; setFocusedValue(params, context.get("focusedValue").add({ months: 1 })); }, focusPreviousMonth(params) { const { context } = params; setFocusedValue(params, context.get("focusedValue").subtract({ months: 1 })); }, setDateValue({ context, event, prop }) { if (!Array.isArray(event.value)) return; const value = event.value.map((date) => (0, import_date_utils.constrainValue)(date, prop("min"), prop("max"))); context.set("value", value); }, clearDateValue({ context }) { context.set("value", []); }, setSelectedDate(params) { const { context, event } = params; const values = Array.from(context.get("value")); const activeIndex = context.get("activeIndex"); const existingValue = values[activeIndex]; const newValue = normalizeValue(params, event.value ?? context.get("focusedValue")); values[activeIndex] = preserveTime(existingValue, newValue); context.set("value", (0, import_date_picker.adjustStartAndEndDate)(values)); }, resetSelection(params) { const { context, event } = params; const existingValue = context.get("value")[0]; const newValue = normalizeValue(params, event.value ?? context.get("focusedValue")); context.set("value", [preserveTime(existingValue, newValue)]); }, toggleSelectedDate(params) { const { context, event } = params; const currentValue = normalizeValue(params, event.value ?? context.get("focusedValue")); const existingValues = context.get("value"); const index = existingValues.findIndex((date) => (0, import_date_utils.isDateEqual)(date, currentValue)); if (index === -1) { const values = [...existingValues, currentValue]; context.set("value", (0, import_date_picker.sortDates)(values)); } else { const values = Array.from(existingValues); values.splice(index, 1); context.set("value", (0, import_date_picker.sortDates)(values)); } }, setHoveredDate({ context, event }) { context.set("hoveredValue", event.value); }, clearHoveredDate({ context }) { context.set("hoveredValue", null); }, selectFocusedDate({ context, computed }) { const values = Array.from(context.get("value")); const activeIndex = context.get("activeIndex"); const existingValue = values[activeIndex]; const newValue = context.get("focusedValue").copy(); values[activeIndex] = preserveTime(existingValue, newValue); context.set("value", (0, import_date_picker.adjustStartAndEndDate)(values)); const valueAsString = computed("valueAsString"); context.set("inputValue", valueAsString[activeIndex]); }, focusPreviousDay(params) { const { context } = params; const nextValue = context.get("focusedValue").subtract({ days: 1 }); setFocusedValue(params, nextValue); }, focusNextDay(params) { const { context } = params; const nextValue = context.get("focusedValue").add({ days: 1 }); setFocusedValue(params, nextValue); }, focusPreviousWeek(params) { const { context } = params; const nextValue = context.get("focusedValue").subtract({ weeks: 1 }); setFocusedValue(params, nextValue); }, focusNextWeek(params) { const { context } = params; const nextValue = context.get("focusedValue").add({ weeks: 1 }); setFocusedValue(params, nextValue); }, focusNextPage(params) { const { context, computed, prop } = params; const nextPage = (0, import_date_utils.getNextPage)( context.get("focusedValue"), context.get("startValue"), computed("visibleDuration"), prop("locale"), prop("min"), prop("max") ); setAdjustedValue(params, nextPage); }, focusPreviousPage(params) { const { context, computed, prop } = params; const previousPage = (0, import_date_utils.getPreviousPage)( context.get("focusedValue"), context.get("startValue"), computed("visibleDuration"), prop("locale"), prop("min"), prop("max") ); setAdjustedValue(params, previousPage); }, focusSectionStart(params) { const { context } = params; setFocusedValue(params, context.get("startValue").copy()); }, focusSectionEnd(params) { const { computed } = params; setFocusedValue(params, computed("endValue").copy()); }, focusNextSection(params) { const { context, event, computed, prop } = params; const nextSection = (0, import_date_utils.getNextSection)( context.get("focusedValue"), context.get("startValue"), event.larger, computed("visibleDuration"), prop("locale"), prop("min"), prop("max") ); if (!nextSection) return; setAdjustedValue(params, nextSection); }, focusPreviousSection(params) { const { context, event, computed, prop } = params; const previousSection = (0, import_date_utils.getPreviousSection)( context.get("focusedValue"), context.get("startValue"), event.larger, computed("visibleDuration"), prop("locale"), prop("min"), prop("max") ); if (!previousSection) return; setAdjustedValue(params, previousSection); }, focusNextYear(params) { const { context } = params; const nextValue = context.get("focusedValue").add({ years: 1 }); setFocusedValue(params, nextValue); }, focusPreviousYear(params) { const { context } = params; const nextValue = context.get("focusedValue").subtract({ years: 1 }); setFocusedValue(params, nextValue); }, focusNextDecade(params) { const { context } = params; const nextValue = context.get("focusedValue").add({ years: 10 }); setFocusedValue(params, nextValue); }, focusPreviousDecade(params) { const { context } = params; const nextValue = context.get("focusedValue").subtract({ years: 10 }); setFocusedValue(params, nextValue); }, clearFocusedDate(params) { const { context, prop } = params; const calendar = context.get("focusedValue").calendar; setFocusedValue(params, (0, import_date_utils.getTodayDate)(prop("timeZone"), calendar)); }, focusPreviousMonthColumn(params) { const { context, event } = params; const nextValue = context.get("focusedValue").subtract({ months: event.columns }); setFocusedValue(params, nextValue); }, focusNextMonthColumn(params) { const { context, event } = params; const nextValue = context.get("focusedValue").add({ months: event.columns }); setFocusedValue(params, nextValue); }, focusPreviousYearColumn(params) { const { context, event } = params; const nextValue = context.get("focusedValue").subtract({ years: event.columns }); setFocusedValue(params, nextValue); }, focusNextYearColumn(params) { const { context, event } = params; const nextValue = context.get("focusedValue").add({ years: event.columns }); setFocusedValue(params, nextValue); }, focusFirstMonth(params) { const { context } = params; const focused = context.get("focusedValue"); const minMonth = focused.calendar.getMinimumMonthInYear?.(focused) ?? 1; setFocusedValue(params, focused.set({ month: minMonth })); }, focusLastMonth(params) { const { context } = params; const focused = context.get("focusedValue"); const maxMonth = focused.calendar.getMonthsInYear(focused); setFocusedValue(params, focused.set({ month: maxMonth })); }, focusFirstYear(params) { const { context } = params; const range = (0, import_date_utils.getDecadeRange)(context.get("focusedValue").year); const nextValue = context.get("focusedValue").set({ year: range[0] }); setFocusedValue(params, nextValue); }, focusLastYear(params) { const { context } = params; const range = (0, import_date_utils.getDecadeRange)(context.get("focusedValue").year); const nextValue = context.get("focusedValue").set({ year: range[range.length - 1] }); setFocusedValue(params, nextValue); }, setActiveIndex({ context, event }) { context.set("activeIndex", event.index); }, setActiveIndexToEnd({ context }) { context.set("activeIndex", 1); }, setActiveIndexToStart({ context }) { context.set("activeIndex", 0); }, focusActiveCell({ scope, context, event }) { if (event.src === "input.click") return; (0, import_dom_query.raf)(() => { const view = context.get("view"); dom.getFocusedCell(scope, view)?.focus({ preventScroll: true }); }); }, focusActiveCellIfNeeded({ scope, context, event }) { if (!event.focus) return; (0, import_dom_query.raf)(() => { const view = context.get("view"); dom.getFocusedCell(scope, view)?.focus({ preventScroll: true }); }); }, setHoveredValueIfKeyboard({ context, event, prop }) { if (!event.type.startsWith("TABLE.ARROW") || prop("selectionMode") !== "range" || context.get("activeIndex") === 0) return; context.set("hoveredValue", context.get("focusedValue").copy()); }, focusTriggerElement({ scope }) { (0, import_dom_query.raf)(() => { dom.getTriggerEl(scope)?.focus({ preventScroll: true }); }); }, focusFirstInputElement({ scope, event }) { if (event.focus === false) return; (0, import_dom_query.raf)(() => { const [inputEl] = dom.getInputEls(scope); const elementToFocus = inputEl ?? dom.getTriggerEl(scope); elementToFocus?.focus({ preventScroll: true }); }); }, focusInputElement({ scope }) { (0, import_dom_query.raf)(() => { const inputEls = dom.getInputEls(scope); if (inputEls.length === 0) { dom.getTriggerEl(scope)?.focus({ preventScroll: true }); return; } const lastIndexWithValue = inputEls.findLastIndex((inputEl2) => inputEl2.value !== ""); const indexToFocus = Math.max(lastIndexWithValue, 0); const inputEl = inputEls[indexToFocus]; inputEl?.focus({ preventScroll: true }); inputEl?.setSelectionRange(inputEl.value.length, inputEl.value.length); }); }, syncMonthSelectElement({ scope, context }) { const monthSelectEl = dom.getMonthSelectEl(scope); (0, import_dom_query.setElementValue)(monthSelectEl, context.get("startValue").month.toString()); }, syncYearSelectElement({ scope, context }) { const yearSelectEl = dom.getYearSelectEl(scope); (0, import_dom_query.setElementValue)(yearSelectEl, context.get("startValue").year.toString()); }, setInputValue({ context, event }) { if (context.get("activeIndex") !== event.index) return; context.set("inputValue", event.value); }, syncInputValue({ scope, context, event }) { queueMicrotask(() => { const inputEls = dom.getInputEls(scope); const idx = event.index ?? context.get("activeIndex"); (0, import_dom_query.setElementValue)(inputEls[idx], context.get("inputValue")); }); }, focusParsedDate(params) { const { event, prop } = params; if (event.index == null) return; const parse = prop("parse"); const date = parse(event.value, { locale: prop("locale"), timeZone: prop("timeZone") }); if (!date || !(0, import_date_picker.isValidDate)(date)) return; setFocusedValue(params, date); }, selectParsedDate({ context, event, prop }) { if (event.index == null) return; const parse = prop("parse"); let date = parse(event.value, { locale: prop("locale"), timeZone: prop("timeZone") }); if (!date || !(0, import_date_picker.isValidDate)(date)) { if (event.value) { date = context.get("focusedValue").copy(); } } if (!date) return; date = (0, import_date_utils.constrainValue)(date, prop("min"), prop("max")); const values = Array.from(context.get("value")); values[event.index] = date; context.set("value", values); const valueAsString = getValueAsString(values, prop); context.set("inputValue", valueAsString[event.index]); }, resetView({ context }) { context.set("view", context.initial("view")); }, setStartValue({ context, computed, prop }) { const focusedValue = context.get("focusedValue"); const outside = (0, import_date_utils.isDateOutsideRange)(focusedValue, context.get("startValue"), computed("endValue")); if (!outside) return; const startValue = (0, import_date_utils.alignDate)(focusedValue, "start", { months: prop("numOfMonths") }, prop("locale")); context.set("startValue", startValue); }, invokeOnOpen({ prop, context }) { if (prop("inline")) return; prop("onOpenChange")?.({ open: true, value: context.get("value") }); }, invokeOnClose({ prop, context }) { if (prop("inline")) return; prop("onOpenChange")?.({ open: false, value: context.get("value") }); }, invokeOnVisibleRangeChange({ prop, context, computed }) { prop("onVisibleRangeChange")?.({ view: context.get("view"), visibleRange: computed("visibleRange") }); }, toggleVisibility({ event, send, prop }) { send({ type: prop("open") ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: event }); } } } }); var normalizeValue = (ctx, value) => { const { context, prop } = ctx; const view = context.get("view"); let dateValue = typeof value === "number" ? context.get("focusedValue").set({ [view]: value }) : value; (0, import_date_picker.eachView)((view2) => { if ((0, import_date_picker.isBelowMinView)(view2, prop("minView"))) { dateValue = dateValue.set({ [view2]: view2 === "day" ? 1 : 0 }); } }); return dateValue; }; var preserveTime = (existingDate, newDate) => { if (!existingDate || !("hour" in existingDate)) { return newDate; } const isZoned = "timeZone" in existingDate; let dateWithTime = newDate; if (!("hour" in newDate)) { if (isZoned) { dateWithTime = (0, import_date.toZoned)((0, import_date.toCalendarDateTime)(newDate), existingDate.timeZone); } else { dateWithTime = (0, import_date.toCalendarDateTime)(newDate); } } return dateWithTime.set({ hour: existingDate.hour, minute: existingDate.minute, second: existingDate.second, millisecond: existingDate.millisecond }); }; function setFocusedValue(ctx, mixedValue) { const { context, prop, computed } = ctx; if (!mixedValue) return; const value = normalizeValue(ctx, mixedValue); if ((0, import_date_utils.isDateEqual)(context.get("focusedValue"), value)) return; const adjustFn = (0, import_date_utils.getAdjustedDateFn)(computed("visibleDuration"), prop("locale"), prop("min"), prop("max")); const adjustedValue = adjustFn({ focusedDate: value, startDate: context.get("startValue") }); context.set("startValue", adjustedValue.startDate); context.set("focusedValue", adjustedValue.focusedDate); } function setAdjustedValue(ctx, value) { const { context } = ctx; context.set("startValue", value.startDate); const focusedValue = context.get("focusedValue"); if ((0, import_date_utils.isDateEqual)(focusedValue, value.focusedDate)) return; context.set("focusedValue", value.focusedDate); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { machine });