@codecademy/gamut
68.2.268.2.3-alpha.794432.0
dist/DatePicker/utils/locale.js+
dist/DatePicker/utils/locale.jsNew file+93
Index: package/dist/DatePicker/utils/locale.js
===================================================================
--- package/dist/DatePicker/utils/locale.js
+++ package/dist/DatePicker/utils/locale.js
@@ -0,0 +1,93 @@
+// Replaces `Intl.Locale` when missing or incomplete (e.g. no `getWeekInfo` in Firefox).
+// https://formatjs.github.io/docs/polyfills/intl-locale/
+import '@formatjs/intl-locale/polyfill.js';
+import { useEffect, useMemo, useState } from 'react';
+
+/**
+ * The runtime default locale string (user agent), matching what `Intl` uses when no locale is passed.
+ */
+export const getDefaultLocaleTag = () => new Intl.DateTimeFormat().resolvedOptions().locale;
+
+/**
+ * Resolves `Intl.LocalesArgument` (or `undefined`) to a stable `Intl.Locale` instance for formatting
+ * and locale metadata (e.g. `getWeekInfo()` in supporting environments).
+ *
+ * - `undefined` → default runtime locale via {@link getDefaultLocaleTag}
+ * - `Intl.Locale` → returned as-is (no duplicate allocation)
+ * - `string` / `readonly string[]` → `new Intl.Locale(...)`
+ */
+export const resolveLocale = locales => {
+ if (locales === undefined) {
+ return new Intl.Locale(getDefaultLocaleTag());
+ }
+ if (locales instanceof Intl.Locale) {
+ return locales;
+ }
+ if (typeof locales === 'string') {
+ return new Intl.Locale(locales);
+ }
+ const first = locales[0];
+ if (first === undefined) {
+ return new Intl.Locale(getDefaultLocaleTag());
+ }
+ if (typeof first === 'string') {
+ return new Intl.Locale(first);
+ }
+ return first instanceof Intl.Locale ? first : new Intl.Locale(String(first));
+};
+
+/**
+ * Memoized {@link resolveLocale} for calendar subcomponents. Pass the same `locale` prop you accept
+ * from `CalendarBaseProps` (optional `Intl.LocalesArgument`).
+ */
+export const useResolvedLocale = locale => useMemo(() => resolveLocale(locale), [locale]);
+
+/**
+ * Convert an Intl.Locale to a string. This is necessary the Intl.DateTimeFormat constructor only accepts a string in some versions of TS.
+ * @param locale - The Intl.Locale to convert to a string.
+ * @returns The stringified locale.
+ */
+export const stringifyLocale = locale => locale.toString();
+
+/** ISO weekday: 1 = Monday … 7 = Sunday (matches `Intl.Locale#getWeekInfo().firstDay`). */
+
+/** `getWeekInfo` is stage-3; typings may lag behind runtime / polyfill. */
+
+/**
+ * First calendar column weekday from `locale` (via `getWeekInfo()`), or explicit override.
+ * - `weekStartsOnOverride` — ISO weekday **1–7** (Monday … Sunday), same as `getWeekInfo().firstDay`
+ * - omitted → `locale.getWeekInfo().firstDay` when available, else **7** (Sunday)
+ */
+export const getIsoFirstDayFromLocale = (locale, weekStartsOnOverride) => {
+ if (weekStartsOnOverride) return weekStartsOnOverride;
+ try {
+ const getWeekInfo = locale.getWeekInfo?.bind(locale);
+ if (typeof getWeekInfo === 'function') {
+ const {
+ firstDay
+ } = getWeekInfo();
+ if (typeof firstDay === 'number' && firstDay >= 1 && firstDay <= 7) {
+ return firstDay;
+ }
+ }
+ } catch {
+ /* ignore */
+ }
+ return 7;
+};
+
+/**
+ * Hook: resolved first weekday for the calendar grid. Re-reads after mount so async polyfills
+ * (e.g. Firefox) can install `getWeekInfo` before the first paint in some bundles.
+ */
+export const useIsoFirstWeekday = (locale, weekStartsOnOverride) => {
+ const [firstDay, setFirstDay] = useState(() => getIsoFirstDayFromLocale(locale, weekStartsOnOverride));
+ useEffect(() => {
+ setFirstDay(getIsoFirstDayFromLocale(locale, weekStartsOnOverride));
+ const t = setTimeout(() => {
+ setFirstDay(getIsoFirstDayFromLocale(locale, weekStartsOnOverride));
+ }, 0);
+ return () => clearTimeout(t);
+ }, [locale, weekStartsOnOverride]);
+ return firstDay;
+};
\ No newline at end of file