UNPKG

react-prayer-widget

Version:

Embeddable prayer times widget components for React applications

1,391 lines (1,388 loc) 220 kB
import { getCustomAzanName, getCustomAzanGlobalName, removeCustomAzanFileGlobal, getAzanSource, removeCustomAzanFile, storeCustomAzanFile } from './chunk-DVY2OY7Q.js'; import { Globe, ChevronDown, CheckIcon, SearchIcon, Sun, Moon, Sunset, Sunrise, Calendar, MapPin, Settings, Monitor, Bell, Calculator, Pause, Volume2, CircleAlert, Play, SkipForward, XIcon, ChevronDownIcon, Minus, Plus, Rows, Columns, ChevronUpIcon, MousePointer2, Move, Shapes, Layers, Frame, SlidersHorizontal, FileDown, Share2, CircleUserRound, Palette, Edit2, Lock, Pipette, PipetteIcon } from 'lucide-react'; import React, { createContext, memo, useRef, useState, useMemo, useCallback, useEffect, forwardRef, useContext, isValidElement, Fragment as Fragment$1, useImperativeHandle } from 'react'; import { motion, AnimatePresence, isMotionComponent, useMotionValue, useSpring, useInView, useTransform } from 'motion/react'; import { getTimezone, getTimezonesForCountry } from 'countries-and-timezones'; import { jsx, jsxs, Fragment } from 'react/jsx-runtime'; import Color from 'color'; import { Slot } from '@radix-ui/react-slot'; import { cva } from 'class-variance-authority'; import { clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; import * as LabelPrimitive from '@radix-ui/react-label'; import * as PopoverPrimitive from '@radix-ui/react-popover'; import { Tabs as Tabs$1, Slider } from 'radix-ui'; import * as SelectPrimitive from '@radix-ui/react-select'; import useMeasure from 'react-use-measure'; import { allCountries } from 'country-region-data'; import * as DialogPrimitive from '@radix-ui/react-dialog'; import * as SwitchPrimitive from '@radix-ui/react-switch'; import { countries } from 'country-data-list'; import { CircleFlag } from 'react-circle-flags'; import { Command as Command$1 } from 'cmdk'; import * as ContextMenuPrimitive from '@radix-ui/react-context-menu'; import * as SliderPrimitive from '@radix-ui/react-slider'; // shared/lib/geo/country.ts var countryNameToISO2 = { "saudi arabia": "SA", "kingdom of saudi arabia": "SA", "united arab emirates": "AE", uae: "AE", kuwait: "KW", qatar: "QA", bahrain: "BH", oman: "OM", iraq: "IQ", syria: "SY", lebanon: "LB", jordan: "JO", palestine: "PS", egypt: "EG", morocco: "MA", tunisia: "TN", algeria: "DZ", turkey: "TR", pakistan: "PK", bangladesh: "BD", indonesia: "ID", malaysia: "MY", "united kingdom": "GB", uk: "GB", "great britain": "GB", "united states": "US", usa: "US", canada: "CA", australia: "AU" }; function iso2ToFlag(iso2) { const code = iso2.trim().toUpperCase(); if (code.length !== 2) { return ""; } const A = 127462; const base = "A".charCodeAt(0); const chars = Array.from(code).map( (ch) => String.fromCodePoint(A + (ch.charCodeAt(0) - base)) ); return chars.join(""); } function countryToFlag(countryOrCode) { if (!countryOrCode) { return ""; } const val = countryOrCode.trim(); if (val.length === 2) { return iso2ToFlag(val); } const iso = countryNameToISO2[val.toLowerCase()]; return iso ? iso2ToFlag(iso) : ""; } // shared/lib/time/format.ts var HOURS_IN_HALF_DAY = 12; var HOUR_RESET = 0; var PM_THRESHOLD = 12; var TIME_REGEX = /(\d{1,2}):(\d{2})/; function getPeriod(isPM, locale) { if (isPM) { return locale === "ar" ? "\u0645" : "PM"; } return locale === "ar" ? "\u0635" : "AM"; } function formatTimeDisplay(time24h, use24Hour, locale = "en") { const sanitized = sanitizeTimeString(time24h); if (use24Hour) { return sanitized; } const [hStr, mStr] = sanitized.split(":"); const hours = Number(hStr); const isPM = hours >= PM_THRESHOLD; const period = getPeriod(isPM, locale); const hour12 = hours % HOURS_IN_HALF_DAY === HOUR_RESET ? HOURS_IN_HALF_DAY : hours % HOURS_IN_HALF_DAY; return `${hour12}:${mStr} ${period}`; } function formatMinutesHHmm(totalMinutes) { const hours = Math.floor(totalMinutes / 60); const minutes = totalMinutes % 60; const hh = String(hours).padStart(2, "0"); const mm = String(minutes).padStart(2, "0"); return `${hh}:${mm}`; } function sanitizeTimeString(raw) { if (!raw) { return "00:00"; } const match = raw.match(TIME_REGEX); if (!match) { return "00:00"; } let h = Number(match[1]); let m = Number(match[2]); if (!(Number.isFinite(h) && Number.isFinite(m))) { return "00:00"; } const MAX_HOURS = 23; const MAX_MINUTES = 59; h = Math.max(0, Math.min(MAX_HOURS, h)); m = Math.max(0, Math.min(MAX_MINUTES, m)); return `${String(h).padStart(2, "0")}:${String(m).padStart(2, "0")}`; } function formatCurrentTime(date, use24Hour, language = "en") { const hours = date.getHours(); const minutes = date.getMinutes(); if (use24Hour) { return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`; } try { const base = language === "ar" ? "ar-SA" : "en-US"; return new Intl.DateTimeFormat(base, { hour: "2-digit", minute: "2-digit", hour12: true }).format(date); } catch { const isPM = hours >= PM_THRESHOLD; const period = getPeriod(isPM, language); const hour12 = hours % HOURS_IN_HALF_DAY === HOUR_RESET ? HOURS_IN_HALF_DAY : hours % HOURS_IN_HALF_DAY; return `${hour12}:${String(minutes).padStart(2, "0")} ${period}`; } } function useControlledState(props) { const { value, defaultValue, onChange } = props; const [state, setInternalState] = useState( value !== void 0 ? value : defaultValue ); useEffect(() => { if (value !== void 0) { setInternalState(value); } }, [value]); const setState = useCallback( (next, ...args) => { setInternalState(next); onChange?.(next, ...args); }, [onChange] ); return [state, setState]; } function useIsInView(ref, options = {}) { const { inView, inViewOnce = false, inViewMargin = "0px" } = options; const localRef = useRef(null); useImperativeHandle(ref, () => localRef.current); const inViewResult = useInView(localRef, { once: inViewOnce, margin: inViewMargin }); const isInView = !inView || inViewResult; return { ref: localRef, isInView }; } var COUNTRY_TO_TZ_DEFAULT = { SA: "Asia/Mecca", AE: "Asia/Dubai", KW: "Asia/Kuwait", QA: "Asia/Qatar", BH: "Asia/Bahrain", OM: "Asia/Muscat", IQ: "Asia/Baghdad", SY: "Asia/Damascus", LB: "Asia/Beirut", JO: "Asia/Amman", PS: "Asia/Jerusalem", EG: "Africa/Cairo", MA: "Africa/Casablanca", TN: "Africa/Tunis", DZ: "Africa/Algiers", TR: "Europe/Istanbul", PK: "Asia/Karachi", BD: "Asia/Dhaka", ID: "Asia/Jakarta", MY: "Asia/Kuala_Lumpur", GB: "Europe/London", US: "America/New_York", CA: "America/Toronto", AU: "Australia/Sydney" }; function guessTimezoneFromCountryCode(alpha2) { return COUNTRY_TO_TZ_DEFAULT[alpha2.toUpperCase()]; } function getCountryPrimaryTimezone(alpha2) { const cc = alpha2.toUpperCase(); const tzInfos = getTimezonesForCountry(cc); if (tzInfos && tzInfos.length > 0) { const sorted = [...tzInfos].sort((a, b) => { const aPop = a.population || 0; const bPop = b.population || 0; return bPop - aPop; }); return sorted[0]?.name; } return guessTimezoneFromCountryCode(cc); } function getCountryUtcOffsetLabel(alpha2) { const tzName = getCountryPrimaryTimezone(alpha2); if (!tzName) { return "GMT+0"; } const tzInfo = getTimezone(tzName); if (!tzInfo || typeof tzInfo.utcOffset !== "number") { return "GMT+0"; } const offset = tzInfo.utcOffset; if (offset === 0) { return "GMT+0"; } const sign = offset >= 0 ? "+" : "-"; const abs = Math.abs(offset); const hours = Math.floor(abs / 60); const mins = abs % 60; if (mins === 0) { return `GMT${sign}${hours}`; } return `GMT${sign}${hours}:${String(mins).padStart(2, "0")}`; } function getCountryCodeFromTimezone(timezone) { try { const info = getTimezone(timezone); if (!info) { return; } const countries2 = info.countries; if (Array.isArray(countries2) && countries2.length > 0) { return countries2[0]?.toUpperCase(); } } catch { } return; } // shared/config/translations.ts var translations = { en: { settings: { title: "Prayer Settings", locationTimezone: "Location & Timezone", displayOptions: "Display", horizontalPrayerList: "Vertical first", verticalFirst: "Vertical first", general: "General", calculation: "Calculation", azan: "Azan", showOtherPrayers: "Show Other Prayer Cards", showCity: "Show Current City", showTicker: "Show Ticker", showClock: "Show Clock", showDate: "Show Date", calculationMethod: "Calculation Method", asrCalculation: "Asr Calculation", timeAdjustments: "Time Adjustments (minutes)", timeAdjustmentsHelp: "Adjust prayer times by \xB130 minutes to match your local mosque or preference", done: "Done", timeFormat24h: "24-hour Time", dimPreviousPrayers: "Dim Previous Prayers", language: "Language", autoDetectTimezone: "Auto-detect timezone", locationPermissionDenied: "Location permission denied. Auto-detect is off. Defaulting to Makkah Al-Mukarramah, Saudi Arabia.", tickerSpeed: "Ticker change interval" }, azan: { enable: "Enable Azan", volume: "Volume", volumeLowWarning: "Volume might be too low to hear", volumeZeroWarning: "Volume is muted. Azan will not play", type: "Azan type", customOverride: "Custom (overrides all)", perPrayer: "Per\u2011prayer", full: "Full", short: "Short", beepOnly: "Beep only", customFile: "Custom file", selected: "Selected:", preview: "Preview azan" }, uploader: { dragOr: "Drag a file here or", browse: "browse", dropHere: "Drop file here" }, general: { remaining: "remaining", loading: "Loading...", remainingTillAzan: "remaining time till azan" }, prayers: { fajr: "Fajr", sunrise: "Sunrise", dhuhr: "Dhuhr", jumuah: "Jumu\u02BFah", asr: "Asr", maghrib: "Maghrib", isha: "Isha" }, dates: { hijriMonths: [ "Muharram", "Safar", "Rabi' al-Awwal", "Rabi' al-Thani", "Jumada al-Awwal", "Jumada al-Thani", "Rajab", "Sha'ban", "Ramadan", "Shawwal", "Dhu al-Qi'dah", "Dhu al-Hijjah" ] } }, ar: { settings: { title: "\u0625\u0639\u062F\u0627\u062F\u0627\u062A \u0627\u0644\u0635\u0644\u0627\u0629", locationTimezone: "\u0627\u0644\u0645\u0648\u0642\u0639 \u0648\u0627\u0644\u0645\u0646\u0637\u0642\u0629 \u0627\u0644\u0632\u0645\u0646\u064A\u0629", displayOptions: "\u0627\u0644\u0639\u0631\u0636", horizontalPrayerList: "\u0627\u0644\u0639\u0631\u0636 \u0627\u0644\u0639\u0645\u0648\u062F\u064A \u0623\u0648\u0644\u064B\u0627", verticalFirst: "\u0627\u0644\u0639\u0631\u0636 \u0627\u0644\u0639\u0645\u0648\u062F\u064A \u0623\u0648\u0644\u064B\u0627", general: "\u0639\u0627\u0645", calculation: "\u0627\u0644\u062D\u0633\u0627\u0628", azan: "\u0627\u0644\u0623\u0630\u0627\u0646", showOtherPrayers: "\u0625\u0638\u0647\u0627\u0631 \u0628\u0637\u0627\u0642\u0627\u062A \u0627\u0644\u0635\u0644\u0648\u0627\u062A \u0627\u0644\u0623\u062E\u0631\u0649", showCity: "\u0625\u0638\u0647\u0627\u0631 \u0627\u0644\u0645\u062F\u064A\u0646\u0629 \u0627\u0644\u062D\u0627\u0644\u064A\u0629", showTicker: "\u0625\u0638\u0647\u0627\u0631 \u0627\u0644\u0634\u0631\u064A\u0637 \u0627\u0644\u0645\u062A\u062D\u0631\u0643", showClock: "\u0625\u0638\u0647\u0627\u0631 \u0627\u0644\u0633\u0627\u0639\u0629", showDate: "\u0625\u0638\u0647\u0627\u0631 \u0627\u0644\u062A\u0627\u0631\u064A\u062E", calculationMethod: "\u0637\u0631\u064A\u0642\u0629 \u0627\u0644\u062D\u0633\u0627\u0628", asrCalculation: "\u062D\u0633\u0627\u0628 \u0627\u0644\u0639\u0635\u0631", timeAdjustments: "\u062A\u0639\u062F\u064A\u0644 \u0627\u0644\u0623\u0648\u0642\u0627\u062A (\u0628\u0627\u0644\u062F\u0642\u0627\u0626\u0642)", timeAdjustmentsHelp: "\u0627\u0636\u0628\u0637 \u0623\u0648\u0642\u0627\u062A \u0627\u0644\u0635\u0644\u0627\u0629 \xB130 \u062F\u0642\u064A\u0642\u0629 \u0644\u062A\u0648\u0627\u0641\u0642 \u0645\u0633\u062C\u062F\u0643 \u0627\u0644\u0645\u062D\u0644\u064A", done: "\u062A\u0645", timeFormat24h: "\u0646\u0638\u0627\u0645 24 \u0633\u0627\u0639\u0629", dimPreviousPrayers: "\u062A\u0639\u062A\u064A\u0645 \u0627\u0644\u0635\u0644\u0648\u0627\u062A \u0627\u0644\u0633\u0627\u0628\u0642\u0629", language: "\u0627\u0644\u0644\u063A\u0629", autoDetectTimezone: "\u0627\u0643\u062A\u0634\u0627\u0641 \u0627\u0644\u0645\u0646\u0637\u0642\u0629 \u0627\u0644\u0632\u0645\u0646\u064A\u0629 \u062A\u0644\u0642\u0627\u0626\u064A\u064B\u0627", locationPermissionDenied: "\u062A\u0645 \u0631\u0641\u0636 \u0625\u0630\u0646 \u0627\u0644\u0645\u0648\u0642\u0639. \u0627\u0644\u0627\u0643\u062A\u0634\u0627\u0641 \u0627\u0644\u062A\u0644\u0642\u0627\u0626\u064A \u063A\u064A\u0631 \u0645\u064F\u0641\u0639\u0644. \u0633\u064A\u062A\u0645 \u0627\u0644\u0627\u0641\u062A\u0631\u0627\u0636\u064A \u0625\u0644\u0649 \u0645\u0643\u0629 \u0627\u0644\u0645\u0643\u0631\u0645\u0629\u060C \u0627\u0644\u0633\u0639\u0648\u062F\u064A\u0629.", tickerSpeed: "\u0645\u062F\u0629 \u062A\u0628\u062F\u064A\u0644 \u0627\u0644\u0634\u0631\u064A\u0637" }, azan: { enable: "\u062A\u0641\u0639\u064A\u0644 \u0627\u0644\u0623\u0630\u0627\u0646", volume: "\u0645\u0633\u062A\u0648\u0649 \u0627\u0644\u0635\u0648\u062A", volumeLowWarning: "\u0645\u0633\u062A\u0648\u0649 \u0627\u0644\u0635\u0648\u062A \u0642\u062F \u064A\u0643\u0648\u0646 \u0645\u0646\u062E\u0641\u0636\u064B\u0627 \u062C\u062F\u064B\u0627 \u0644\u0633\u0645\u0627\u0639\u0647", volumeZeroWarning: "\u0627\u0644\u0635\u0648\u062A \u0645\u0639\u0637\u0644. \u0644\u0646 \u064A\u062A\u0645 \u062A\u0634\u063A\u064A\u0644 \u0627\u0644\u0623\u0630\u0627\u0646", type: "\u0646\u0648\u0639 \u0627\u0644\u0623\u0630\u0627\u0646", customOverride: "\u0645\u062E\u0635\u0635 (\u064A\u0633\u062A\u0628\u062F\u0644 \u0627\u0644\u0643\u0644)", perPrayer: "\u0644\u0643\u0644 \u0635\u0644\u0627\u0629", full: "\u0643\u0627\u0645\u0644", short: "\u0642\u0635\u064A\u0631", beepOnly: "\u062A\u0646\u0628\u064A\u0647 \u0641\u0642\u0637", customFile: "\u0645\u0644\u0641 \u0645\u062E\u0635\u0635", selected: "\u0627\u0644\u0645\u062D\u062F\u062F:", preview: "\u0645\u0639\u0627\u064A\u0646\u0629 \u0627\u0644\u0623\u0630\u0627\u0646" }, uploader: { dragOr: "\u0627\u0633\u062D\u0628 \u0645\u0644\u0641\u064B\u0627 \u0647\u0646\u0627 \u0623\u0648", browse: "\u062A\u0635\u0641\u062D", dropHere: "\u0623\u0641\u0644\u062A \u0627\u0644\u0645\u0644\u0641 \u0647\u0646\u0627" }, general: { remaining: "\u0645\u062A\u0628\u0642\u064A", loading: "\u062C\u0627\u0631\u064A \u0627\u0644\u062A\u062D\u0645\u064A\u0644...", remainingTillAzan: "\u0627\u0644\u0648\u0642\u062A \u0627\u0644\u0645\u062A\u0628\u0642\u064A \u062D\u062A\u0649 \u0627\u0644\u0623\u0630\u0627\u0646" }, prayers: { fajr: "\u0627\u0644\u0641\u062C\u0631", sunrise: "\u0627\u0644\u0634\u0631\u0648\u0642", dhuhr: "\u0627\u0644\u0638\u0647\u0631", jumuah: "\u0627\u0644\u062C\u0645\u0639\u0629", asr: "\u0627\u0644\u0639\u0635\u0631", maghrib: "\u0627\u0644\u0645\u063A\u0631\u0628", isha: "\u0627\u0644\u0639\u0634\u0627\u0621" }, dates: { hijriMonths: [ "\u0645\u062D\u0631\u0645", "\u0635\u0641\u0631", "\u0631\u0628\u064A\u0639 \u0627\u0644\u0623\u0648\u0644", "\u0631\u0628\u064A\u0639 \u0627\u0644\u0622\u062E\u0631", "\u062C\u0645\u0627\u062F\u0649 \u0627\u0644\u0623\u0648\u0644\u0649", "\u062C\u0645\u0627\u062F\u0649 \u0627\u0644\u0622\u062E\u0631\u0629", "\u0631\u062C\u0628", "\u0634\u0639\u0628\u0627\u0646", "\u0631\u0645\u0636\u0627\u0646", "\u0634\u0648\u0627\u0644", "\u0630\u0648 \u0627\u0644\u0642\u0639\u062F\u0629", "\u0630\u0648 \u0627\u0644\u062D\u062C\u0629" ] } } }; var TranslationContext = createContext( void 0 ); function TranslationProvider({ children, language }) { const t = (key) => { const keys = key.split("."); let value = translations[language]; for (const k of keys) { if (value && typeof value === "object" && value !== null) { value = value[k]; } else { return key; } } return typeof value === "string" ? value : key; }; return /* @__PURE__ */ jsx(TranslationContext.Provider, { value: { t, language }, children }); } function useTranslation() { const context = useContext(TranslationContext); if (!context) { throw new Error("useTranslation must be used within a TranslationProvider"); } return context; } var DATE_UPDATE_INTERVAL_MS = 6e4; function formatHijriDate(now, language) { const islamicLocale = language === "ar" ? "ar-SA" : "en"; const tryFormats = [ `${islamicLocale}-u-ca-islamic-umalqura`, `${islamicLocale}-u-ca-islamic` ]; for (const loc of tryFormats) { try { const hijri = new Intl.DateTimeFormat(loc, { day: "numeric", month: "long", year: "numeric" }).format(now); if (hijri) { return hijri; } } catch { } } return now.toLocaleDateString(language === "ar" ? "ar" : "en-US", { weekday: "short", month: "short", day: "numeric", year: "numeric" }); } function DualDateDisplay({ className }) { const { language } = useTranslation(); const [dates, setDates] = useState(null); useEffect(() => { const updateDates = () => { const now = /* @__PURE__ */ new Date(); const gregorian = now.toLocaleDateString( language === "ar" ? "ar" : "en-US", { weekday: "short", month: "short", day: "numeric", year: "numeric" } ); const hijri = formatHijriDate(now, language); setDates({ gregorian, hijri }); }; updateDates(); const interval = setInterval(updateDates, DATE_UPDATE_INTERVAL_MS); return () => clearInterval(interval); }, [language]); if (!dates) { return null; } return /* @__PURE__ */ jsxs("div", { className: `flex items-center gap-3 ${className}`, children: [ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 text-amber-400", children: /* @__PURE__ */ jsx(Calendar, { className: "h-4 w-4" }) }), /* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [ /* @__PURE__ */ jsx("div", { className: "font-medium text-foreground text-sm", children: dates.gregorian }), /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-xs", children: dates.hijri }) ] }) ] }); } function TopBar({ showDate = true, showClock = true, showCity = true, currentTime, location, timeFormat24h = true, language = "en", className, classes }) { return /* @__PURE__ */ jsxs( "div", { className: `flex items-center justify-between ${className ?? ""} ${classes?.container ?? ""}`, children: [ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [ !!showDate && /* @__PURE__ */ jsx(DualDateDisplay, { className: classes?.date }), !!showClock && /* @__PURE__ */ jsx( "div", { className: `font-mono text-muted-foreground text-xs ${classes?.clock ?? ""}`, children: formatCurrentTime(currentTime, timeFormat24h, language) } ), !!showCity && /* @__PURE__ */ jsxs( "div", { className: `flex items-center gap-1 text-muted-foreground text-xs ${classes?.city ?? ""}`, children: [ /* @__PURE__ */ jsx(MapPin, { className: `h-3 w-3 ${classes?.cityIcon ?? ""}` }), /* @__PURE__ */ jsx("span", { children: location?.city || (language === "ar" ? "\u062C\u0627\u0631\u064A \u0627\u0644\u062A\u062D\u0645\u064A\u0644..." : "Loading...") }), /* @__PURE__ */ jsx("span", { className: "ml-1", children: location?.countryCode ? countryToFlag(location.countryCode) : countryToFlag(location?.country || "") }) ] } ) ] }), /* @__PURE__ */ jsx("div", {}) ] } ); } function cn(...inputs) { return twMerge(clsx(inputs)); } var buttonVariants = cva( "inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md font-medium text-sm outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", { variants: { variant: { default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40", outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", link: "text-primary underline-offset-4 hover:underline" }, size: { default: "h-9 px-4 py-2 has-[>svg]:px-3", sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5", lg: "h-10 rounded-md px-6 has-[>svg]:px-4", icon: "size-9" } }, defaultVariants: { variant: "default", size: "default" } } ); function Button({ className, variant, size, asChild = false, ...props }) { const buttonClassName = cn(buttonVariants({ variant, size, className })); if (asChild) { const slotProps = props; return /* @__PURE__ */ jsx(Slot, { className: buttonClassName, "data-slot": "button", ...slotProps }); } return /* @__PURE__ */ jsx("button", { className: buttonClassName, "data-slot": "button", ...props }); } function Label({ className, ...props }) { return /* @__PURE__ */ jsx( LabelPrimitive.Root, { className: cn( "flex select-text items-center gap-2 font-medium text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50", className ), "data-slot": "label", ...props } ); } function Popover({ ...props }) { return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props }); } function PopoverTrigger({ ...props }) { return /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props }); } function PopoverContent({ className, align = "center", sideOffset = 4, ...props }) { return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx( PopoverPrimitive.Content, { align, className: cn( "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in", className ), "data-slot": "popover-content", sideOffset, ...props } ) }); } function Input({ className, type, ...props }) { return /* @__PURE__ */ jsx( "input", { className: cn( "flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs outline-none transition-[color,box-shadow] selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:font-medium file:text-foreground file:text-sm placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30", "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50", "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40", className ), "data-slot": "input", type, ...props } ); } function Select({ ...props }) { return /* @__PURE__ */ jsx(SelectPrimitive.Root, { "data-slot": "select", ...props }); } function SelectValue({ ...props }) { return /* @__PURE__ */ jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props }); } function SelectTrigger({ className, size = "default", children, ...props }) { return /* @__PURE__ */ jsxs( SelectPrimitive.Trigger, { className: cn( "flex w-fit items-center justify-between gap-2 whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs outline-none transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[size=default]:h-9 data-[size=sm]:h-8 data-[placeholder]:text-muted-foreground *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:hover:bg-input/50 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0", className ), "data-size": size, "data-slot": "select-trigger", ...props, children: [ children, /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 opacity-50" }) }) ] } ); } function SelectContent({ className, children, position = "popper", ...props }) { const viewportRef = useRef(null); useEffect(() => { const el = viewportRef.current?.querySelector( "[data-state='checked']" ); if (el && typeof el.scrollIntoView === "function") { el.scrollIntoView({ block: "center" }); } }, []); return /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs( SelectPrimitive.Content, { className: cn( "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in", position === "popper" && "data-[side=left]:-translate-x-1 data-[side=top]:-translate-y-1 data-[side=right]:translate-x-1 data-[side=bottom]:translate-y-1", className ), "data-slot": "select-content", position, ...props, children: [ /* @__PURE__ */ jsx(SelectScrollUpButton, {}), /* @__PURE__ */ jsx( SelectPrimitive.Viewport, { className: cn( "p-1", position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1" ), ref: viewportRef, children } ), /* @__PURE__ */ jsx(SelectScrollDownButton, {}) ] } ) }); } function SelectItem({ className, children, ...props }) { return /* @__PURE__ */ jsxs( SelectPrimitive.Item, { className: cn( "relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className ), "data-slot": "select-item", ...props, children: [ /* @__PURE__ */ jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, { className: "size-4" }) }) }), /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children }) ] } ); } function SelectScrollUpButton({ className, ...props }) { return /* @__PURE__ */ jsx( SelectPrimitive.ScrollUpButton, { className: cn( "flex cursor-default items-center justify-center py-1", className ), "data-slot": "select-scroll-up-button", ...props, children: /* @__PURE__ */ jsx(ChevronUpIcon, { className: "size-4" }) } ); } function SelectScrollDownButton({ className, ...props }) { return /* @__PURE__ */ jsx( SelectPrimitive.ScrollDownButton, { className: cn( "flex cursor-default items-center justify-center py-1", className ), "data-slot": "select-scroll-down-button", ...props, children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4" }) } ); } var HSL_MAX_SATURATION = 100; var HSL_MAX_LIGHTNESS = 100; var HSL_DEFAULT_LIGHTNESS = 50; var ALPHA_MAX = 100; var FULL_ALPHA = 1; var ALMOST_ZERO_THRESHOLD = 0.01; var LIGHTNESS_RANGE = 50; var ColorPickerContext = createContext( void 0 ); var useColorPicker = () => { const context = useContext(ColorPickerContext); if (!context) { throw new Error("useColorPicker must be used within a ColorPickerProvider"); } return context; }; var ColorPicker = ({ value, defaultValue = "#000000", onChange, className, ...props }) => { const resolveHsl = (input) => { try { return Color(input).hsl(); } catch { return Color(defaultValue).hsl(); } }; const initial = resolveHsl(value ?? defaultValue); const [hue, setHue] = useState(initial.hue() || 0); const [saturation, setSaturation] = useState( initial.saturationl() || HSL_MAX_SATURATION ); const [lightness, setLightness] = useState( initial.lightness() || HSL_DEFAULT_LIGHTNESS ); const [alpha, setAlpha] = useState( Math.round((initial.alpha() ?? FULL_ALPHA) * ALPHA_MAX) ); const [mode, setMode] = useState("hex"); useEffect(() => { if (value === void 0 || value === null) { return; } try { const c = Color(value).hsl(); const nextHue = c.hue() || 0; const nextSat = c.saturationl() || 0; const nextLight = c.lightness() || 0; const nextAlpha = Math.round((c.alpha() ?? FULL_ALPHA) * ALPHA_MAX); setHue(nextHue); setSaturation(nextSat); setLightness(nextLight); setAlpha(nextAlpha); } catch { } }, [value]); useEffect(() => { if (onChange) { const color = Color.hsl(hue, saturation, lightness).alpha( alpha / ALPHA_MAX ); const rgba = color.rgb().array(); onChange([rgba[0], rgba[1], rgba[2], alpha / ALPHA_MAX]); } }, [hue, saturation, lightness, alpha, onChange]); return /* @__PURE__ */ jsx( ColorPickerContext.Provider, { value: { hue, saturation, lightness, alpha, mode, setHue, setSaturation, setLightness, setAlpha, setMode }, children: /* @__PURE__ */ jsx( "div", { className: cn("flex size-full flex-col gap-4", className), ...props } ) } ); }; var ColorPickerSelection = memo( ({ className, ...props }) => { const containerRef = useRef(null); const [isDragging, setIsDragging] = useState(false); const [positionX, setPositionX] = useState(0); const [positionY, setPositionY] = useState(0); const { hue, saturation, lightness, setSaturation, setLightness } = useColorPicker(); const backgroundGradient = useMemo( () => `linear-gradient(0deg, rgba(0,0,0,1), rgba(0,0,0,0)), linear-gradient(90deg, rgba(255,255,255,1), rgba(255,255,255,0)), hsl(${hue}, 100%, 50%)`, [hue] ); const handlePointerMove = useCallback( (event) => { if (!(isDragging && containerRef.current)) { return; } const rect = containerRef.current.getBoundingClientRect(); const x = Math.max( 0, Math.min(1, (event.clientX - rect.left) / rect.width) ); const y = Math.min(1, (event.clientY - rect.top) / rect.height); setPositionX(x); setPositionY(y); setSaturation(x * HSL_MAX_SATURATION); const topLightness = x < ALMOST_ZERO_THRESHOLD ? HSL_MAX_LIGHTNESS : HSL_DEFAULT_LIGHTNESS + LIGHTNESS_RANGE * (1 - x); const calculatedLightness = topLightness * (1 - y); setLightness(calculatedLightness); }, [isDragging, setSaturation, setLightness] ); useEffect(() => { const handlePointerUp = () => setIsDragging(false); if (isDragging) { window.addEventListener("pointermove", handlePointerMove); window.addEventListener("pointerup", handlePointerUp); } return () => { window.removeEventListener("pointermove", handlePointerMove); window.removeEventListener("pointerup", handlePointerUp); }; }, [isDragging, handlePointerMove]); useEffect(() => { if (isDragging) { return; } const x = Math.max( 0, Math.min(1, (saturation ?? 0) / HSL_MAX_SATURATION) ); const denom = HSL_MAX_LIGHTNESS - LIGHTNESS_RANGE * x; const ratio = denom > 0 ? (lightness ?? 0) / denom : 0; const y = 1 - Math.max(0, Math.min(1, ratio)); setPositionX(x); setPositionY(y); }, [saturation, lightness, isDragging]); return /* @__PURE__ */ jsx( "div", { className: cn("relative size-full cursor-crosshair rounded", className), onPointerDown: (e) => { e.preventDefault(); setIsDragging(true); handlePointerMove(e.nativeEvent); }, ref: containerRef, style: { background: backgroundGradient }, ...props, children: /* @__PURE__ */ jsx( "div", { className: "-translate-x-1/2 -translate-y-1/2 pointer-events-none absolute h-4 w-4 rounded-full border-2 border-white", style: { left: `${positionX * HSL_MAX_SATURATION}%`, top: `${positionY * HSL_MAX_SATURATION}%`, boxShadow: "0 0 0 1px rgba(0,0,0,0.5)" } } ) } ); } ); ColorPickerSelection.displayName = "ColorPickerSelection"; var ColorPickerHue = ({ className, ...props }) => { const { hue, setHue } = useColorPicker(); return /* @__PURE__ */ jsxs( Slider.Root, { className: cn("relative flex h-4 w-full touch-none", className), max: 360, onValueChange: ([newHue]) => setHue(newHue), step: 1, value: [hue], ...props, children: [ /* @__PURE__ */ jsx(Slider.Track, { className: "relative my-0.5 h-3 w-full grow rounded-full bg-[linear-gradient(90deg,#FF0000,#FFFF00,#00FF00,#00FFFF,#0000FF,#FF00FF,#FF0000)]", children: /* @__PURE__ */ jsx(Slider.Range, { className: "absolute h-full" }) }), /* @__PURE__ */ jsx(Slider.Thumb, { className: "block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" }) ] } ); }; var ColorPickerAlpha = ({ className, ...props }) => { const { alpha, setAlpha } = useColorPicker(); return /* @__PURE__ */ jsxs( Slider.Root, { className: cn("relative flex h-4 w-full touch-none", className), max: 100, onValueChange: ([newAlpha]) => setAlpha(newAlpha), step: 1, value: [alpha], ...props, children: [ /* @__PURE__ */ jsxs( Slider.Track, { className: "relative my-0.5 h-3 w-full grow rounded-full", style: { background: 'url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==") left center' }, children: [ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-full bg-linear-to-r from-transparent to-black/50" }), /* @__PURE__ */ jsx(Slider.Range, { className: "absolute h-full rounded-full bg-transparent" }) ] } ), /* @__PURE__ */ jsx(Slider.Thumb, { className: "block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" }) ] } ); }; var ColorPickerEyeDropper = ({ className, ...props }) => { const { setHue, setSaturation, setLightness, setAlpha } = useColorPicker(); const handleEyeDropper = async () => { try { const eyeDropper = new EyeDropper(); const result = await eyeDropper.open(); const color = Color(result.sRGBHex); const [h, s, l] = color.hsl().array(); setHue(h); setSaturation(s); setLightness(l); setAlpha(ALPHA_MAX); } catch { } }; return /* @__PURE__ */ jsx( Button, { className: cn("shrink-0 text-muted-foreground", className), onClick: handleEyeDropper, size: "icon", type: "button", variant: "outline", ...props, children: /* @__PURE__ */ jsx(PipetteIcon, { size: 16 }) } ); }; var formats = ["hex", "rgb", "css", "hsl"]; var ColorPickerOutput = ({ className, ...props }) => { const { mode, setMode } = useColorPicker(); return /* @__PURE__ */ jsxs(Select, { onValueChange: setMode, value: mode, children: [ /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 w-20 shrink-0 text-xs", ...props, children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Mode" }) }), /* @__PURE__ */ jsx(SelectContent, { children: formats.map((format) => /* @__PURE__ */ jsx(SelectItem, { className: "text-xs", value: format, children: format.toUpperCase() }, format)) }) ] }); }; function ColorPickerGroup({ label, value, onChange, ariaLabel }) { const safeHex = (val) => { try { const c = Array.isArray(val) ? Color.rgb( val ) : Color(String(val || "#ffffff")); return c.hex().toLowerCase(); } catch { return "#ffffff"; } }; return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-2", children: [ /* @__PURE__ */ jsx(Label, { className: "whitespace-nowrap text-sm", children: label }), /* @__PURE__ */ jsxs(Popover, { children: [ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { "aria-label": ariaLabel || `Pick ${label} color`, className: "flex h-8 w-8 items-center justify-center rounded-md p-0", style: { backgroundColor: value || "#ffffff" }, type: "button", variant: "outline", children: /* @__PURE__ */ jsx(Pipette, { className: "h-3.5 w-3.5 opacity-80" }) } ) }), /* @__PURE__ */ jsx(PopoverContent, { className: "w-80", children: /* @__PURE__ */ jsxs( ColorPicker, { onChange: (val) => onChange(safeHex(val)), value: value || "#ffffff", children: [ /* @__PURE__ */ jsx(ColorPickerSelection, { className: "h-28" }), /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [ /* @__PURE__ */ jsx(ColorPickerEyeDropper, {}), /* @__PURE__ */ jsxs("div", { className: "grid w-full gap-1", children: [ /* @__PURE__ */ jsx(ColorPickerHue, {}), /* @__PURE__ */ jsx(ColorPickerAlpha, {}) ] }) ] }), /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx(ColorPickerOutput, {}) }) ] } ) }) ] }) ] }); } function getStrictContext(name) { const Context = createContext(void 0); const Provider = ({ value, children }) => /* @__PURE__ */ jsx(Context.Provider, { value, children }); const useSafeContext = () => { const ctx = useContext(Context); if (ctx === void 0) { throw new Error(`useContext must be used within ${name}`); } return ctx; }; return [Provider, useSafeContext]; } function mergeRefs(...refs) { return (node) => { for (const ref of refs) { if (!ref) { continue; } if (typeof ref === "function") { ref(node); } else { ref.current = node; } } }; } function mergeProps(childProps, slotProps) { const merged = { ...childProps, ...slotProps }; if (childProps.className || slotProps.className) { merged.className = cn( childProps.className, slotProps.className ); } if (childProps.style || slotProps.style) { merged.style = { ...childProps.style, ...slotProps.style }; } return merged; } function Slot2({ children, ref, ...props }) { const isAlreadyMotion = isValidElement(children) && typeof children.type === "object" && children.type !== null && isMotionComponent(children.type); const Base = useMemo(() => { if (isAlreadyMotion && isValidElement(children)) { return children.type; } if (isValidElement(children)) { return motion.create(children.type); } return motion.div; }, [isAlreadyMotion, children]); if (!isValidElement(children)) { const divProps = props; return /* @__PURE__ */ jsx(motion.div, { ...divProps, ref, children }); } const { ref: childRef, ...childProps } = children.props; const mergedProps = mergeProps(childProps, props); return /* @__PURE__ */ jsx(Base, { ...mergedProps, ref: mergeRefs(childRef, ref) }); } var MODULO_DIVISOR = 10; var HALFWAY_OFFSET = 5; var THOUSAND_SEPARATOR_INTERVAL = 3; function SlidingNumberRoller({ prevValue, value, place, transition: transition2, delay = 0 }) { const startNumber = Math.floor(prevValue / place) % MODULO_DIVISOR; const targetNumber = Math.floor(value / place) % MODULO_DIVISOR; const animatedValue = useSpring(startNumber, transition2); useEffect(() => { const timeoutId = setTimeout(() => { animatedValue.set(targetNumber); }, delay); return () => clearTimeout(timeoutId); }, [targetNumber, animatedValue, delay]); const [measureRef, { height }] = useMeasure(); return /* @__PURE__ */ jsxs( "span", { "data-slot": "sliding-number-roller", ref: measureRef, style: { position: "relative", display: "inline-block", width: "1ch", overflowX: "visible", overflowY: "clip", lineHeight: 1, fontVariantNumeric: "tabular-nums" }, children: [ /* @__PURE__ */ jsx("span", { style: { visibility: "hidden" }, children: "0" }), Array.from({ length: MODULO_DIVISOR }, (_, i) => /* @__PURE__ */ jsx( SlidingNumberDisplay, { height, motionValue: animatedValue, number: i, transition: transition2 }, i.toString() )) ] } ); } function SlidingNumberDisplay({ motionValue, number, height, transition: transition2 }) { const y = useTransform(motionValue, (latest) => { if (!height) { return 0; } const currentNumber = latest % MODULO_DIVISOR; const offset = (MODULO_DIVISOR + number - currentNumber) % MODULO_DIVISOR; let translateY = offset * height; if (offset > HALFWAY_OFFSET) { translateY -= MODULO_DIVISOR * height; } return translateY; }); if (!height) { return /* @__PURE__ */ jsx("span", { style: { visibility: "hidden", position: "absolute" }, children: number }); } return /* @__PURE__ */ jsx( motion.span, { "data-slot": "sliding-number-display", style: { y, position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" }, transition: { ...transition2, type: "spring" }, children: number } ); } function SlidingNumber({ ref, number, fromNumber, onNumberChange, inView = false, inViewMargin = "0px", inViewOnce = true, padStart = false, decimalSeparator = ".", decimalPlaces = 0, thousandSeparator, transition: transition2 = { stiffness: 200, damping: 20, mass: 0.4 }, delay = 0, ...props }) { const { ref: localRef, isInView } = useIsInView(ref, { inView, inViewOnce, inViewMargin }); const prevNumberRef = useRef(0); const hasAnimated = fromNumber !== void 0; const motionVal = useMotionValue(fromNumber ?? 0); const springVal = useSpring(motionVal, { stiffness: 90, damping: 50 }); useEffect(() => { if (!hasAnimated) { return; } const timeoutId = setTimeout(() => { if (isInView) { motionVal.set(number); } }, delay); return () => clearTimeout(timeoutId); }, [hasAnimated, isInView, number, motionVal, delay]); const [effectiveNumber, setEffectiveNumber] = useState(0); useEffect(() => { if (hasAnimated) { const inferredDecimals = typeof decimalPlaces === "number" && decimalPlaces >= 0 ? decimalPlaces : (() => { const s = String(number); const idx = s.indexOf("."); return idx >= 0 ? s.length - idx - 1 : 0; })(); const factor = 10 ** inferredDecimals; const unsubscribe = springVal.on( "change", (latestValue) => { const latest = typeof latestValue === "number" ? latestValue : Number.parseFloat(String(latestValue)); const newValue = inferredDecimals > 0 ? Math.round(latest * factor) / factor : Math.round(latest); if (effectiveNumber !== newValue) { setEffectiveNumber(newValue); onNumberChange?.(newValue); } } ); return () => unsubscribe(); } setEffectiveNumber(isInView ? Math.abs(Number(number)) : 0); }, [ hasAnimated, springVal, isInView, number, decimalPlaces, onNumberChange, effectiveNumber ]); const formatNumber = useCallback( (num) => decimalPlaces !== null ? num.toFixed(decimalPlaces) : num.toString(), [decimalPlaces] ); const numberStr = formatNumber(effectiveNumber); const [newIntStrRaw, newDecStrRaw = ""] = numberStr.split("."); const finalIntLength = padStart ? Math.max( Math.floor(Math.abs(number)).toString().length, newIntStrRaw.length ) : newIntStrRaw.length; const newIntStr = padStart ? newIntStrRaw.padStart(finalIntLength, "0") : newIntStrRaw; const prevFormatted = formatNumber(prevNumberRef.current); const [prevIntStrRaw = "", prevDecStrRaw = ""] = prevFormatted.split("."); const prevIntStr = padStart ? prevIntStrRaw.padStart(finalIntLength, "0") : prevIntStrRaw; const adjustedPrevInt = useMemo( () => prevIntStr.length > finalIntLength ? prevIntStr.slice(-finalIntLength) : prevIntStr.padStart(finalIntLength, "0"), [prevIntStr, finalIntLength] ); const adjustedPrevDec = useMemo(() => { if (!newDecStrRaw) { return ""; } return prevDecStrRaw.length > newDecStrRaw.length ? prevDecStrRaw.slice(0, newDecStrRaw.length) : prevDecStrRaw.padEnd(newDecStrRaw.length, "0"); }, [prevDecStrRaw, newDecStrRaw]); useEffect(() => { if (isInView) { prevNumberRef.current = effectiveNumber; } }, [effectiveNumber, isInView]); const intPlaces = useMemo( () => Array.from( { length: finalIntLength }, (_, i) => MODULO_DIVISOR ** (finalIntLength - i - 1) ), [finalIntLength] ); const decPlaces = useMemo( () => newDecStrRaw ? Array.from( { length: newDecStrRaw.length }, (_, i) => MODULO_DIVISOR ** (newDecStrRaw.length - i - 1) ) : [], [newDecStrRaw] ); const newDecValue = newDecStrRaw ? Number.parseInt(newDecStrRaw, 10) : 0; const prevDecValue = adjustedPrevDec ? Number.parseInt(adjustedPrevDec, 10) : 0; return /* @__PURE__ */ jsxs( "span", { "data-slot": "sliding-number", ref: localRef, style: { display: "inline-flex", alignItems: "center" }, ...props, children: [ !!isInView && Number(number) < 0 && /* @__PURE__ */ jsx("span", { style: { marginRight: "0.25rem" }, children: "-" }), intPlac