UNPKG

react-multi-timezone-viewer

Version:
244 lines 9.1 kB
// src/multi-timezone-viewer.tsx import { useEffect, useRef, useState } from "react"; import { DateTime } from "luxon"; import { timeZonesNames } from "@vvo/tzdb"; import { Fragment, jsx, jsxs } from "react/jsx-runtime"; var STORAGE_KEY = "multi_tz_zones"; var allTimezones = timeZonesNames.map((tz) => { const now = DateTime.now().setZone(tz); const offset = now.offset / 60; const sign = offset >= 0 ? "+" : "-"; const offsetHours = Math.floor(Math.abs(offset)); const offsetMinutes = Math.abs(now.offset % 60); return { label: `${tz} (UTC${sign}${offsetHours.toString().padStart(2, "0")}:${offsetMinutes.toString().padStart(2, "0")})`, value: tz, offset }; }).sort((a, b) => a.offset - b.offset).map(({ label, value }) => ({ label, value })); var getUserTimezones = () => { const stored = localStorage.getItem(STORAGE_KEY); return stored ? JSON.parse(stored) : [Intl.DateTimeFormat().resolvedOptions().timeZone]; }; var setUserTimezones = (zones) => { localStorage.setItem(STORAGE_KEY, JSON.stringify(zones)); }; var MultiTimezoneViewer = ({ datetime, dateTimeZone, useCrossSiteStorage = false, customStyles = {} }) => { const baseTime = DateTime.fromFormat(datetime, "yyyy-MM-dd HH:mm:ss", { zone: dateTimeZone }); const [timezones, setTimezones] = useState([]); const [showTooltip, setShowTooltip] = useState(false); const [tooltipPos, setTooltipPos] = useState({ top: 0, left: 0 }); const [showDialog, setShowDialog] = useState(false); const iframeRef = useRef(null); const [hoveringText, setHoveringText] = useState(false); const [hoveringTooltip, setHoveringTooltip] = useState(false); useEffect(() => { if (!hoveringText && !hoveringTooltip) { const timeout = setTimeout(() => { setShowTooltip(false); }, 100); return () => clearTimeout(timeout); } }, [hoveringText, hoveringTooltip]); useEffect(() => { if (useCrossSiteStorage) { window.addEventListener("message", (e) => { if (e.data?.type === "RETURN_TIMEZONES") { setTimezones(e.data.zones); } }); const iframe = document.createElement("iframe"); iframe.src = "https://www.explisoft.com/npm/react-multi-timezone-viewer/script.html"; iframe.style.display = "none"; document.body.appendChild(iframe); iframeRef.current = iframe; iframe.onload = () => { iframe.contentWindow?.postMessage("GET_TIMEZONES", "*"); }; } else { setTimezones(getUserTimezones()); } }, [useCrossSiteStorage]); const handleSave = (zones) => { setTimezones(zones); if (useCrossSiteStorage && iframeRef.current) { iframeRef.current.contentWindow?.postMessage({ type: "SET_TIMEZONES", zones }, "*"); } else { setUserTimezones(zones); } }; const handleMouseEnter = (e) => { const spacing = 10; const tooltipWidth = 260; const tooltipHeight = 200; let left = e.clientX; let top = e.clientY; if (left + tooltipWidth > window.innerWidth) { left = window.innerWidth - tooltipWidth - spacing; } if (top + tooltipHeight > window.innerHeight) { top = window.innerHeight - tooltipHeight - spacing; } setTooltipPos({ top: top + window.scrollY + spacing, left: left + window.scrollX + spacing }); setShowTooltip(true); }; return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( "span", { onMouseEnter: (e) => { setHoveringText(true); handleMouseEnter(e); }, onMouseLeave: () => setHoveringText(false), style: { display: "inline", cursor: "pointer", textDecoration: "none", ...customStyles.container }, children: baseTime.toFormat("ff") } ), showTooltip && /* @__PURE__ */ jsxs( "div", { onMouseEnter: () => setHoveringTooltip(true), onMouseLeave: () => setHoveringTooltip(false), style: { position: "absolute", top: tooltipPos.top, left: tooltipPos.left, background: "#fff", border: "1px solid #ccc", padding: "10px", borderRadius: "4px", zIndex: 1e3, boxShadow: "0 4px 8px rgba(0,0,0,0.1)", maxWidth: "400px", maxHeight: "300px", overflowY: "auto", textAlign: "left", ...customStyles.tooltip }, children: [ /* @__PURE__ */ jsxs( "div", { style: { display: "flex", justifyContent: "space-between", marginBottom: "8px", fontWeight: "bold", ...customStyles.tooltipHeader }, children: [ /* @__PURE__ */ jsx("span", { children: "\u{1F552} Timezones" }), /* @__PURE__ */ jsx( "span", { style: { cursor: "pointer" }, onClick: () => { setShowDialog(true); setShowTooltip(false); }, children: "\u2699\uFE0F" } ) ] } ), /* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse" }, children: /* @__PURE__ */ jsx("tbody", { children: timezones.map((tz) => { const time = baseTime.setZone(tz).toFormat("ff"); return /* @__PURE__ */ jsxs("tr", { children: [ /* @__PURE__ */ jsx("td", { style: { padding: "4px 8px", verticalAlign: "top", textAlign: "left" }, children: tz }), /* @__PURE__ */ jsx("td", { style: { padding: "4px 8px", verticalAlign: "top", textAlign: "left" }, children: /* @__PURE__ */ jsx("strong", { children: time }) }) ] }, tz); }) }) }), useCrossSiteStorage && iframeRef.current && /* @__PURE__ */ jsxs("div", { style: { marginTop: "10px", fontSize: "11px", color: "#888", textAlign: "right" }, children: [ "Powered by ", /* @__PURE__ */ jsx("a", { href: "https://www.explisoft.com", target: "_blank", rel: "noopener noreferrer", children: "explisoft.com" }) ] }) ] } ), showDialog && /* @__PURE__ */ jsx( "div", { style: { position: "fixed", top: 0, left: 0, right: 0, bottom: 0, background: "rgba(0,0,0,0.3)", zIndex: 100, ...customStyles.dialogOverlay }, onClick: () => setShowDialog(false), children: /* @__PURE__ */ jsxs( "div", { onClick: (e) => e.stopPropagation(), style: { background: "#fff", padding: "20px", borderRadius: "8px", width: "400px", maxHeight: "80vh", overflowY: "auto", margin: "5% auto", textAlign: "left", position: "relative", ...customStyles.dialogBox }, children: [ /* @__PURE__ */ jsx( "span", { onClick: () => setShowDialog(false), style: { position: "absolute", top: 10, right: 15, cursor: "pointer" }, children: "\u274C" } ), /* @__PURE__ */ jsx("h3", { children: "Select Timezones" }), /* @__PURE__ */ jsx("div", { style: { margin: "10px 0" }, children: allTimezones.map((tz) => /* @__PURE__ */ jsxs( "label", { style: { display: "block", marginBottom: "5px", fontSize: "14px", cursor: "pointer", ...customStyles.checkboxLabel }, children: [ /* @__PURE__ */ jsx( "input", { type: "checkbox", checked: timezones.includes(tz.value), onChange: (e) => { const newZones = e.target.checked ? [...timezones, tz.value] : timezones.filter((z) => z !== tz.value); handleSave(newZones); } } ), " ", tz.label ] }, tz.value )) }), useCrossSiteStorage && iframeRef.current && /* @__PURE__ */ jsxs("div", { style: { marginTop: "10px", fontSize: "11px", color: "#888", textAlign: "right" }, children: [ "Powered by ", /* @__PURE__ */ jsx("a", { href: "https://www.explisoft.com", target: "_blank", rel: "noopener noreferrer", children: "explisoft.com" }) ] }) ] } ) } ) ] }); }; var multi_timezone_viewer_default = MultiTimezoneViewer; export { multi_timezone_viewer_default as MultiTimezoneViewer }; //# sourceMappingURL=index.mjs.map