@zag-js/date-picker
Version:
Core logic for the date-picker widget implemented as a state machine
167 lines (166 loc) • 5.42 kB
JavaScript
// src/date-picker.utils.ts
import { DateFormatter } from "@internationalized/date";
import { memo } from "@zag-js/core";
import { getDecadeRange } from "@zag-js/date-utils";
import { clampValue, match } from "@zag-js/utils";
function adjustStartAndEndDate(value) {
const [startDate, endDate] = value;
let result;
if (!startDate || !endDate) result = value;
else result = startDate.compare(endDate) <= 0 ? value : [endDate, startDate];
return result;
}
function isDateWithinRange(date, value) {
const [startDate, endDate] = value;
if (!startDate || !endDate) return false;
return startDate.compare(date) <= 0 && endDate.compare(date) >= 0;
}
function sortDates(values) {
return values.slice().filter((date) => date != null).sort((a, b) => a.compare(b));
}
function getRoleDescription(view) {
return match(view, {
year: "calendar decade",
month: "calendar year",
day: "calendar month"
});
}
var PLACEHOLDERS = {
day: "dd",
month: "mm",
year: "yyyy"
};
function getInputPlaceholder(locale) {
return new DateFormatter(locale).formatToParts(/* @__PURE__ */ new Date()).map((item) => PLACEHOLDERS[item.type] ?? item.value).join("");
}
var isValidDate = (value) => {
return !Number.isNaN(value.day) && !Number.isNaN(value.month) && !Number.isNaN(value.year);
};
var defaultTranslations = {
dayCell(state) {
if (state.unavailable) return `Not available. ${state.valueText}`;
if (state.firstInRange) return `Starting range from ${state.valueText}`;
if (state.lastInRange) return `Range ending at ${state.valueText}`;
if (state.selected) return `Selected date. ${state.valueText}`;
return `Choose ${state.valueText}`;
},
trigger(open) {
return open ? "Close calendar" : "Open calendar";
},
viewTrigger(view) {
return match(view, {
year: "Switch to month view",
month: "Switch to day view",
day: "Switch to year view"
});
},
presetTrigger(value) {
const [start = "", end = ""] = value;
return `select ${start} to ${end}`;
},
prevTrigger(view) {
return match(view, {
year: "Switch to previous decade",
month: "Switch to previous year",
day: "Switch to previous month"
});
},
nextTrigger(view) {
return match(view, {
year: "Switch to next decade",
month: "Switch to next year",
day: "Switch to next month"
});
},
// TODO: Revisit this
placeholder() {
return { day: "dd", month: "mm", year: "yyyy" };
},
content: "calendar",
monthSelect: "Select month",
yearSelect: "Select year",
clearTrigger: "Clear selected dates",
weekColumnHeader: "Wk",
weekNumberCell(weekNumber) {
return `Week ${weekNumber}`;
}
};
function viewToNumber(view, fallback) {
if (!view) return fallback || 0;
return view === "day" ? 0 : view === "month" ? 1 : 2;
}
function viewNumberToView(viewNumber) {
return viewNumber === 0 ? "day" : viewNumber === 1 ? "month" : "year";
}
function clampView(view, minView, maxView) {
return viewNumberToView(
clampValue(viewToNumber(view, 0), viewToNumber(minView, 0), viewToNumber(maxView, 2))
);
}
function isAboveMinView(view, minView) {
return viewToNumber(view, 0) > viewToNumber(minView, 0);
}
function isBelowMinView(view, minView) {
return viewToNumber(view, 0) < viewToNumber(minView, 0);
}
function getNextView(view, minView, maxView) {
const nextViewNumber = viewToNumber(view, 0) + 1;
return clampView(viewNumberToView(nextViewNumber), minView, maxView);
}
function getPreviousView(view, minView, maxView) {
const prevViewNumber = viewToNumber(view, 0) - 1;
return clampView(viewNumberToView(prevViewNumber), minView, maxView);
}
var views = ["day", "month", "year"];
function eachView(cb) {
views.forEach((view) => cb(view));
}
var getVisibleRangeText = memo(
(opts) => [opts.view, opts.startValue.toString(), opts.endValue.toString(), opts.locale],
([view], opts) => {
const { startValue, endValue, locale, timeZone, selectionMode } = opts;
if (view === "year") {
const years = getDecadeRange(startValue.year, { strict: true });
const start2 = years.at(0).toString();
const end2 = years.at(-1).toString();
return { start: start2, end: end2, formatted: `${start2} - ${end2}` };
}
if (view === "month") {
const formatter2 = new DateFormatter(locale, {
year: "numeric",
timeZone,
calendar: startValue.calendar.identifier
});
const start2 = formatter2.format(startValue.toDate(timeZone));
const end2 = formatter2.format(endValue.toDate(timeZone));
const formatted2 = selectionMode === "range" ? `${start2} - ${end2}` : start2;
return { start: start2, end: end2, formatted: formatted2 };
}
const formatter = new DateFormatter(locale, {
month: "long",
year: "numeric",
timeZone,
calendar: startValue.calendar.identifier
});
const start = formatter.format(startValue.toDate(timeZone));
const end = formatter.format(endValue.toDate(timeZone));
const formatted = selectionMode === "range" ? `${start} - ${end}` : start;
return { start, end, formatted };
}
);
export {
adjustStartAndEndDate,
clampView,
defaultTranslations,
eachView,
getInputPlaceholder,
getNextView,
getPreviousView,
getRoleDescription,
getVisibleRangeText,
isAboveMinView,
isBelowMinView,
isDateWithinRange,
isValidDate,
sortDates
};