react-prayer-widget
Version:
Embeddable prayer times widget components for React applications
1,338 lines (1,329 loc) • 233 kB
JavaScript
'use strict';
var lucideReact = require('lucide-react');
var React = require('react');
var react = require('motion/react');
var countriesAndTimezones = require('countries-and-timezones');
var jsxRuntime = require('react/jsx-runtime');
var Color = require('color');
var reactSlot = require('@radix-ui/react-slot');
var classVarianceAuthority = require('class-variance-authority');
var clsx = require('clsx');
var tailwindMerge = require('tailwind-merge');
var LabelPrimitive = require('@radix-ui/react-label');
var PopoverPrimitive = require('@radix-ui/react-popover');
var radixUi = require('radix-ui');
var SelectPrimitive = require('@radix-ui/react-select');
var useMeasure = require('react-use-measure');
var countryRegionData = require('country-region-data');
var DialogPrimitive = require('@radix-ui/react-dialog');
var SwitchPrimitive = require('@radix-ui/react-switch');
var countryDataList = require('country-data-list');
var reactCircleFlags = require('react-circle-flags');
var cmdk = require('cmdk');
var ContextMenuPrimitive = require('@radix-ui/react-context-menu');
var SliderPrimitive = require('@radix-ui/react-slider');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__default = /*#__PURE__*/_interopDefault(React);
var Color__default = /*#__PURE__*/_interopDefault(Color);
var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
var PopoverPrimitive__namespace = /*#__PURE__*/_interopNamespace(PopoverPrimitive);
var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
var useMeasure__default = /*#__PURE__*/_interopDefault(useMeasure);
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
var SwitchPrimitive__namespace = /*#__PURE__*/_interopNamespace(SwitchPrimitive);
var ContextMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(ContextMenuPrimitive);
var SliderPrimitive__namespace = /*#__PURE__*/_interopNamespace(SliderPrimitive);
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// shared/lib/prayer/azan.ts
var azan_exports = {};
__export(azan_exports, {
BUILTIN_AZAN_SOURCES: () => BUILTIN_AZAN_SOURCES,
customStorageKey: () => customStorageKey,
getAzanSource: () => getAzanSource,
getCustomAzanGlobalName: () => getCustomAzanGlobalName,
getCustomAzanName: () => getCustomAzanName,
globalCustomStorageKey: () => globalCustomStorageKey,
removeCustomAzanFile: () => removeCustomAzanFile,
removeCustomAzanFileGlobal: () => removeCustomAzanFileGlobal,
storeCustomAzanFile: () => storeCustomAzanFile,
storeCustomAzanFileGlobal: () => storeCustomAzanFileGlobal
});
function getCustomAzanSource(choice, prayer) {
if (choice === "custom:global") {
const key = globalCustomStorageKey();
const url = typeof localStorage !== "undefined" ? localStorage.getItem(key) : null;
return url || null;
}
const p = choice.split(":")[1];
if (p && p === prayer) {
const key = customStorageKey(p);
const url = typeof localStorage !== "undefined" ? localStorage.getItem(key) : null;
return url || null;
}
return null;
}
function getAzanSource(choice, prayer) {
if (!choice || choice === "default") {
return BUILTIN_AZAN_SOURCES.default;
}
if (choice === "off") {
return null;
}
if (choice in BUILTIN_AZAN_SOURCES) {
return BUILTIN_AZAN_SOURCES[choice];
}
if (choice.startsWith("custom:")) {
return getCustomAzanSource(choice, prayer);
}
return BUILTIN_AZAN_SOURCES[choice] || null;
}
function customStorageKey(prayer) {
return `tawkit:azan:custom:${prayer}`;
}
async function storeCustomAzanFile(prayer, file) {
const dataUrl = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(new Error("Failed to read file"));
reader.onload = () => resolve(String(reader.result));
reader.readAsDataURL(file);
});
localStorage.setItem(customStorageKey(prayer), dataUrl);
localStorage.setItem(`${customStorageKey(prayer)}:name`, file.name);
return { url: dataUrl, name: file.name };
}
function globalCustomStorageKey() {
return "tawkit:azan:custom:GLOBAL";
}
async function storeCustomAzanFileGlobal(file) {
const dataUrl = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = () => reject(new Error("Failed to read file"));
reader.onload = () => resolve(String(reader.result));
reader.readAsDataURL(file);
});
localStorage.setItem(globalCustomStorageKey(), dataUrl);
localStorage.setItem(`${globalCustomStorageKey()}:name`, file.name);
return { url: dataUrl, name: file.name };
}
function removeCustomAzanFileGlobal() {
const key = globalCustomStorageKey();
localStorage.removeItem(key);
localStorage.removeItem(`${key}:name`);
}
function getCustomAzanGlobalName() {
return localStorage.getItem(`${globalCustomStorageKey()}:name`) || void 0;
}
function removeCustomAzanFile(prayer) {
const key = customStorageKey(prayer);
localStorage.removeItem(key);
localStorage.removeItem(`${key}:name`);
}
function getCustomAzanName(prayer) {
return localStorage.getItem(`${customStorageKey(prayer)}:name`) || void 0;
}
var BUILTIN_AZAN_SOURCES;
var init_azan = __esm({
"shared/lib/prayer/azan.ts"() {
BUILTIN_AZAN_SOURCES = {
default: "/audio/audio_azan.mp3",
short: "/audio/short_azan.mp3",
fajr: "/audio/audio_fajr.mp3",
beep: "/audio/w-alert-1.wav"
};
}
});
// 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] = React.useState(
value !== void 0 ? value : defaultValue
);
React.useEffect(() => {
if (value !== void 0) {
setInternalState(value);
}
}, [value]);
const setState = React.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 = React.useRef(null);
React.useImperativeHandle(ref, () => localRef.current);
const inViewResult = react.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 = countriesAndTimezones.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 = countriesAndTimezones.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 = countriesAndTimezones.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 = React.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__ */ jsxRuntime.jsx(TranslationContext.Provider, { value: { t, language }, children });
}
function useTranslation() {
const context = React.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] = React.useState(null);
React.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__ */ jsxRuntime.jsxs("div", { className: `flex items-center gap-3 ${className}`, children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 text-amber-400", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Calendar, { className: "h-4 w-4" }) }),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-foreground text-sm", children: dates.gregorian }),
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs(
"div",
{
className: `flex items-center justify-between ${className ?? ""} ${classes?.container ?? ""}`,
children: [
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
!!showDate && /* @__PURE__ */ jsxRuntime.jsx(DualDateDisplay, { className: classes?.date }),
!!showClock && /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: `font-mono text-muted-foreground text-xs ${classes?.clock ?? ""}`,
children: formatCurrentTime(currentTime, timeFormat24h, language)
}
),
!!showCity && /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
className: `flex items-center gap-1 text-muted-foreground text-xs ${classes?.city ?? ""}`,
children: [
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: `h-3 w-3 ${classes?.cityIcon ?? ""}` }),
/* @__PURE__ */ jsxRuntime.jsx("span", { children: location?.city || (language === "ar" ? "\u062C\u0627\u0631\u064A \u0627\u0644\u062A\u062D\u0645\u064A\u0644..." : "Loading...") }),
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1", children: location?.countryCode ? countryToFlag(location.countryCode) : countryToFlag(location?.country || "") })
]
}
)
] }),
/* @__PURE__ */ jsxRuntime.jsx("div", {})
]
}
);
}
function cn(...inputs) {
return tailwindMerge.twMerge(clsx.clsx(inputs));
}
var buttonVariants = classVarianceAuthority.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__ */ jsxRuntime.jsx(reactSlot.Slot, { className: buttonClassName, "data-slot": "button", ...slotProps });
}
return /* @__PURE__ */ jsxRuntime.jsx("button", { className: buttonClassName, "data-slot": "button", ...props });
}
function Label({
className,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx(
LabelPrimitive__namespace.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__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Root, { "data-slot": "popover", ...props });
}
function PopoverTrigger({
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Trigger, { "data-slot": "popover-trigger", ...props });
}
function PopoverContent({
className,
align = "center",
sideOffset = 4,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
PopoverPrimitive__namespace.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__ */ jsxRuntime.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__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Root, { "data-slot": "select", ...props });
}
function SelectValue({
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Value, { "data-slot": "select-value", ...props });
}
function SelectTrigger({
className,
size = "default",
children,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsxs(
SelectPrimitive__namespace.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__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-4 opacity-50" }) })
]
}
);
}
function SelectContent({
className,
children,
position = "popper",
...props
}) {
const viewportRef = React.useRef(null);
React.useEffect(() => {
const el = viewportRef.current?.querySelector(
"[data-state='checked']"
);
if (el && typeof el.scrollIntoView === "function") {
el.scrollIntoView({ block: "center" });
}
}, []);
return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
SelectPrimitive__namespace.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__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
/* @__PURE__ */ jsxRuntime.jsx(
SelectPrimitive__namespace.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__ */ jsxRuntime.jsx(SelectScrollDownButton, {})
]
}
) });
}
function SelectItem({
className,
children,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsxs(
SelectPrimitive__namespace.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__ */ jsxRuntime.jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "size-4" }) }) }),
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children })
]
}
);
}
function SelectScrollUpButton({
className,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx(
SelectPrimitive__namespace.ScrollUpButton,
{
className: cn(
"flex cursor-default items-center justify-center py-1",
className
),
"data-slot": "select-scroll-up-button",
...props,
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUpIcon, { className: "size-4" })
}
);
}
function SelectScrollDownButton({
className,
...props
}) {
return /* @__PURE__ */ jsxRuntime.jsx(
SelectPrimitive__namespace.ScrollDownButton,
{
className: cn(
"flex cursor-default items-center justify-center py-1",
className
),
"data-slot": "select-scroll-down-button",
...props,
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.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 = React.createContext(
void 0
);
var useColorPicker = () => {
const context = React.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__default.default(input).hsl();
} catch {
return Color__default.default(defaultValue).hsl();
}
};
const initial = resolveHsl(value ?? defaultValue);
const [hue, setHue] = React.useState(initial.hue() || 0);
const [saturation, setSaturation] = React.useState(
initial.saturationl() || HSL_MAX_SATURATION
);
const [lightness, setLightness] = React.useState(
initial.lightness() || HSL_DEFAULT_LIGHTNESS
);
const [alpha, setAlpha] = React.useState(
Math.round((initial.alpha() ?? FULL_ALPHA) * ALPHA_MAX)
);
const [mode, setMode] = React.useState("hex");
React.useEffect(() => {
if (value === void 0 || value === null) {
return;
}
try {
const c = Color__default.default(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]);
React.useEffect(() => {
if (onChange) {
const color = Color__default.default.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__ */ jsxRuntime.jsx(
ColorPickerContext.Provider,
{
value: {
hue,
saturation,
lightness,
alpha,
mode,
setHue,
setSaturation,
setLightness,
setAlpha,
setMode
},
children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: cn("flex size-full flex-col gap-4", className),
...props
}
)
}
);
};
var ColorPickerSelection = React.memo(
({ className, ...props }) => {
const containerRef = React.useRef(null);
const [isDragging, setIsDragging] = React.useState(false);
const [positionX, setPositionX] = React.useState(0);
const [positionY, setPositionY] = React.useState(0);
const { hue, saturation, lightness, setSaturation, setLightness } = useColorPicker();
const backgroundGradient = React.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 = React.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]
);
React.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]);
React.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__ */ jsxRuntime.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__ */ jsxRuntime.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__ */ jsxRuntime.jsxs(
radixUi.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__ */ jsxRuntime.jsx(radixUi.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__ */ jsxRuntime.jsx(radixUi.Slider.Range, { className: "absolute h-full" }) }),
/* @__PURE__ */ jsxRuntime.jsx(radixUi.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__ */ jsxRuntime.jsxs(
radixUi.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__ */ jsxRuntime.jsxs(
radixUi.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__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 rounded-full bg-linear-to-r from-transparent to-black/50" }),
/* @__PURE__ */ jsxRuntime.jsx(radixUi.Slider.Range, { className: "absolute h-full rounded-full bg-transparent" })
]
}
),
/* @__PURE__ */ jsxRuntime.jsx(radixUi.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__default.default(result.sRGBHex);
const [h, s, l] = color.hsl().array();
setHue(h);
setSaturation(s);
setLightness(l);
setAlpha(ALPHA_MAX);
} catch {
}
};
return /* @__PURE__ */ jsxRuntime.jsx(
Button,
{
className: cn("shrink-0 text-muted-foreground", className),
onClick: handleEyeDropper,
size: "icon",
type: "button",
variant: "outline",
...props,
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PipetteIcon, { size: 16 })
}
);
};
var formats = ["hex", "rgb", "css", "hsl"];
var ColorPickerOutput = ({
className,
...props
}) => {
const { mode, setMode } = useColorPicker();
return /* @__PURE__ */ jsxRuntime.jsxs(Select, { onValueChange: setMode, value: mode, children: [
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 w-20 shrink-0 text-xs", ...props, children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "Mode" }) }),
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: formats.map((format) => /* @__PURE__ */ jsxRuntime.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__default.default.rgb(
val
) : Color__default.default(String(val || "#ffffff"));
return c.hex().toLowerCase();
} catch {
return "#ffffff";
}
};
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-2", children: [
/* @__PURE__ */ jsxRuntime.jsx(Label, { className: "whitespace-nowrap text-sm", children: label }),
/* @__PURE__ */ jsxRuntime.jsxs(Popover, { children: [
/* @__PURE__ */ jsxRuntime.jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(lucideReact.Pipette, { className: "h-3.5 w-3.5 opacity-80" })
}
) }),
/* @__PURE__ */ jsxRuntime.jsx(PopoverContent, { className: "w-80", children: /* @__PURE__ */ jsxRuntime.jsxs(
ColorPicker,
{
onChange: (val) => onChange(safeHex(val)),
value: value || "#ffffff",
children: [
/* @__PURE__ */ jsxRuntime.jsx(ColorPickerSelection, { className: "h-28" }),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [
/* @__PURE__ */ jsxRuntime.jsx(ColorPickerEyeDropper, {}),
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid w-full gap-1", children: [
/* @__PURE__ */ jsxRuntime.jsx(ColorPickerHue, {}),
/* @__PURE__ */ jsxRuntime.jsx(ColorPickerAlpha, {})
] })
] }),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsx(ColorPickerOutput, {}) })
]
}
) })
] })
] });
}
function getStrictContext(name) {
const Context = React.createContext(void 0);
const Provider = ({
value,
children
}) => /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value, children });
const useSafeContext = () => {
const ctx = React.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 = React.isValidElement(children) && typeof children.type === "object" && children.type !== null && react.isMotionComponent(children.type);
const Base = React.useMemo(() => {
if (isAlreadyMotion && React.isValidElement(children)) {
return children.type;
}
if (React.isValidElement(children)) {
return react.motion.create(children.type);
}
return react.motion.div;
}, [isAlreadyMotion, children]);
if (!React.isValidElement(children)) {
const divProps = props;
return /* @__PURE__ */ jsxRuntime.jsx(react.motion.div, { ...divProps, ref, children });
}
const { ref: childRef, ...childProps } = children.props;
const mergedProps = mergeProps(childProps, props);
return /* @__PURE__ */ jsxRuntime.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 = react.useSpring(startNumber, transition2);
React.useEffect(() => {
const timeoutId = setTimeout(() => {
animatedValue.set(targetNumber);
}, delay);
return () => clearTimeout(timeoutId);
}, [targetNumber, animatedValue, delay]);
const [measureRef, { height }] = useMeasure__de