UNPKG

@eggtronic/react-weather-widget

Version:
485 lines (464 loc) 27.6 kB
import React, { useRef, useCallback, useEffect, useState } from 'react'; import styled, { ThemeProvider } from 'styled-components'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __makeTemplateObject(cooked, raw) { if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } return cooked; } var defaultTheme = { color: ['#b92b27', '#1565C0'], width: '500px', height: '650px', mainFontSize: '24px', subFontSize: '14px', mainFontColor: '#fff', subFontColor: '#fff', hrColor: '#fff', lineChartPadding: [45, 30], lineChartLabelPadding: [-10, -10], lineChartColor: '#fff', lineChartLabelColor: '#fff', lineChartLabelSize: 1, lineChartHeight: '120px' }; var nightTheme = { color: ['#1F1B24', '#1F1B24'], width: '500px', height: '650px', mainFontSize: '24px', subFontSize: '14px', mainFontColor: '#fff', subFontColor: '#fff', hrColor: '#fff', lineChartPadding: [45, 30], lineChartLabelPadding: [-10, -10], lineChartColor: '#fff', lineChartLabelColor: '#fff', lineChartLabelSize: 1, lineChartHeight: '120px' }; var dayTheme = { color: ['#fff', '#fff'], width: '500px', height: '650px', mainFontSize: '24px', subFontSize: '14px', mainFontColor: '#000', subFontColor: '#000', hrColor: '#000', lineChartPadding: [45, 30], lineChartLabelPadding: [-10, -10], lineChartColor: '#000', lineChartLabelColor: '#000', lineChartLabelSize: 1, lineChartHeight: '120px' }; function useMountedState() { var mountedRef = useRef(false); var get = useCallback(function () { return mountedRef.current; }, []); useEffect(function () { mountedRef.current = true; return function () { mountedRef.current = false; }; }); return get; } function useAsyncFn(fn, deps, initialState) { if (deps === void 0) { deps = []; } if (initialState === void 0) { initialState = { loading: false }; } var lastCallId = useRef(0); var isMounted = useMountedState(); var _a = useState(initialState), state = _a[0], set = _a[1]; var callback = useCallback(function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var callId = ++lastCallId.current; set(function (prevState) { return (__assign(__assign({}, prevState), { loading: true })); }); return fn.apply(void 0, args).then(function (value) { isMounted() && callId === lastCallId.current && set({ value: value, loading: false }); return value; }, function (error) { isMounted() && callId === lastCallId.current && set({ error: error, loading: false }); return error; }); }, deps); return [state, callback]; } /* eslint-disable */ function useAsync(fn, deps) { if (deps === void 0) { deps = []; } var _a = useAsyncFn(fn, deps, { loading: true, }), state = _a[0], callback = _a[1]; useEffect(function () { callback(); }, [callback]); return state; } var useGeolocation = function (hasGeo, options) { var _a = useState({ loading: true, accuracy: null, altitude: null, altitudeAccuracy: null, heading: null, latitude: null, longitude: null, speed: null, timestamp: Date.now(), once: true, shouldDetectLocation: true }), state = _a[0], setState = _a[1]; if (hasGeo && state.shouldDetectLocation) { setState(__assign(__assign({}, state), { shouldDetectLocation: false, loading: false })); } var finishOnce = false; var mounted = true; var watchId; var onEvent = function (event) { if (mounted && !finishOnce) { setState(__assign(__assign({}, state), { loading: false, accuracy: event.coords.accuracy, altitude: event.coords.altitude, altitudeAccuracy: event.coords.altitudeAccuracy, heading: event.coords.heading, latitude: event.coords.latitude, longitude: event.coords.longitude, speed: event.coords.speed, timestamp: event.timestamp })); if (state.once) { finishOnce = true; } } }; var onEventError = function (error) { return mounted && setState(function (oldState) { return (__assign(__assign({}, oldState), { loading: false, error: error })); }); }; useEffect(function () { if (state.shouldDetectLocation) { navigator.geolocation.getCurrentPosition(onEvent, onEventError, options); watchId = navigator.geolocation.watchPosition(onEvent, onEventError, options); } return function () { mounted = false; if (state.shouldDetectLocation) { navigator.geolocation.clearWatch(watchId); } }; }, []); return state; }; var BASE_API_URL = 'https://api.openweathermap.org/data/2.5/onecall?'; var ICON_BASE_URL = 'http://openweathermap.org/img/wn/'; var getHourlyData = function (hourlyData, from, to) { var data = {}; hourlyData.slice(from, to).forEach(function (d) { data[new Date(d.dt * 1000).getHours() + ":00"] = Math.round(d.temp); }); return data; }; /** * * @param key api key from openweathermap * @param units * For temperature in Fahrenheit, use units=imperial * For temperature in Celsius, use units=metric * Kelvin is used by default, so there is no need to use the units parameter in the API call if you want this * @param exclude https://openweathermap.org/api/one-call-api */ function useFetchWeather(key, units, exclude, geo) { var _this = this; var _a, _b, _c; var _d = useGeolocation(!!geo), latitude = _d.latitude, longitude = _d.longitude, loading = _d.loading, error = _d.error, shouldDetectLocation = _d.shouldDetectLocation; var state = useAsync(function () { return __awaiter(_this, void 0, void 0, function () { var url, response, result; return __generator(this, function (_a) { switch (_a.label) { case 0: if (loading) return [2 /*return*/, { loading: true }]; if (error) return [2 /*return*/, { error: error, loading: false }]; url = "" + BASE_API_URL + ("lat=" + ((geo === null || geo === void 0 ? void 0 : geo.lat) || latitude)) + ("&lon=" + ((geo === null || geo === void 0 ? void 0 : geo.lon) || longitude)) + ("" + (units ? "&units=" + units : '')) + ("" + (exclude ? "&exclude=" + exclude.join(',') : '')) + ("&appid=" + key); return [4 /*yield*/, fetch(url)]; case 1: response = _a.sent(); return [4 /*yield*/, response.json()]; case 2: result = _a.sent(); return [2 /*return*/, result]; } }); }); }, [latitude, longitude, loading, error]); var errorMsg = ((_b = (_a = state.value) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.message) || ((_c = state.error) === null || _c === void 0 ? void 0 : _c.message); /** there is a hack to check if it is currently loading geo or weather data * if loading is true then geo is loading. * if geo loaded, and if there is no error and no timezone * then weather is loading. */ var loadingMsg = null; if (shouldDetectLocation) { if (loading) { loadingMsg = 'Geo Locating ...'; } else if (!state.value.timezone && !errorMsg) { loadingMsg = 'Fetching Weather Data ...'; } } if (!shouldDetectLocation) { if (state.loading && !errorMsg) { loadingMsg = 'Fetching Weather Data ...'; } } var weatherData = state.value ? state.value : null; return [errorMsg, loadingMsg, weatherData]; } var WeatherHeaderWrapper = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n width: ", ";\n display: flex;\n justify-content: space-between;\n h1 {\n margin: 2px;\n font-size: ", ";\n color: ", ";\n }\n p {\n color: ", ";\n font-size: ", ";\n padding-right: 8px;\n padding-left: 8px;\n text-align: center;\n }\n"], ["\n width: ", ";\n display: flex;\n justify-content: space-between;\n h1 {\n margin: 2px;\n font-size: ", ";\n color: ", ";\n }\n p {\n color: ", ";\n font-size: ", ";\n padding-right: 8px;\n padding-left: 8px;\n text-align: center;\n }\n"])), function (props) { return props.theme.width; }, function (props) { return props.theme.mainFontSize; }, function (props) { return props.theme.mainFontColor; }, function (props) { return props.theme.subFontColor; }, function (props) { return props.theme.subFontSize; }); var HeaderLeft = styled.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n width: 130px;\n margin-left: 30px;\n text-align: right;\n display: flex;\n align-items: center;\n justify-content: center;\n p {\n margin-top: 2em;\n }\n"], ["\n width: 130px;\n margin-left: 30px;\n text-align: right;\n display: flex;\n align-items: center;\n justify-content: center;\n p {\n margin-top: 2em;\n }\n"]))); var HeaderCenter = styled.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n height: 200px;\n text-align: center;\n margin-top: 10px;\n"], ["\n height: 200px;\n text-align: center;\n margin-top: 10px;\n"]))); var HeaderRight = styled.div(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n width: 130px;\n margin-right: 30px;\n text-align: left;\n display: flex;\n align-items: center;\n justify-content: center;\n p {\n margin-top: 2em;\n }\n"], ["\n width: 130px;\n margin-right: 30px;\n text-align: left;\n display: flex;\n align-items: center;\n justify-content: center;\n p {\n margin-top: 2em;\n }\n"]))); var WeatherIcon = styled.img(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n width: 130px;\n transform: translateY(-20%);\n"], ["\n width: 130px;\n transform: translateY(-20%);\n"]))); function WeatherHeader(_a) { var today = _a.today, current = _a.current, timezone = _a.timezone; return (React.createElement(WeatherHeaderWrapper, null, React.createElement(HeaderLeft, null, React.createElement("br", null), React.createElement("br", null), React.createElement("br", null), React.createElement("p", null, React.createElement("span", { role: "img", "aria-label": "sun" }, "\u2600\uFE0F"), React.createElement("br", null), React.createElement("br", null), Math.round(today.temp.max), "\u00B0C"), React.createElement("br", null), React.createElement("p", null, React.createElement("span", { role: "img", "aria-label": "ice" }, "\u2744\uFE0F"), React.createElement("br", null), React.createElement("br", null), Math.round(today.temp.min), "\u00B0C")), React.createElement(HeaderCenter, null, React.createElement("h1", null, " ", timezone.split('/')[1], " "), React.createElement("h1", null, Math.round(current.temp), "\u00B0C"), React.createElement(WeatherIcon, { src: ICON_BASE_URL + current.weather[0].icon + "@2x.png" }), React.createElement("p", { style: { transform: 'translateY(-280%)' } }, current.weather[0].description)), React.createElement(HeaderRight, null, React.createElement("br", null), React.createElement("br", null), React.createElement("br", null), React.createElement("p", null, React.createElement("span", { role: "img", "aria-label": "wind" }, "\uD83D\uDCA8"), React.createElement("br", null), React.createElement("br", null), current.wind_speed, "m/s"), React.createElement("br", null), React.createElement("p", null, React.createElement("span", { role: "img", "aria-label": "drop" }, "\uD83D\uDCA7"), React.createElement("br", null), React.createElement("br", null), current.humidity, "%")))); } var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5; var LineChartWrapper = styled.div(templateObject_1$1 || (templateObject_1$1 = __makeTemplateObject(["\n height: 120px;\n width: ", ";\n"], ["\n height: 120px;\n width: ", ";\n"])), function (props) { return props.theme.width; }); function LineChart(_a) { var data = _a.data, width = _a.width, height = _a.height, _b = _a.padding, padding = _b === void 0 ? [40, 40] : _b, _c = _a.labelPadding, labelPadding = _c === void 0 ? [-9, -10] : _c, _d = _a.customLabel, customLabel = _d === void 0 ? function (val) { return val + " \u00B0C"; } : _d, _e = _a.lineWidth, lineWidth = _e === void 0 ? 2 : _e, _f = _a.lineColor, lineColor = _f === void 0 ? '#000' : _f, _g = _a.labelSize, labelSize = _g === void 0 ? 1 : _g, _h = _a.labelColor, labelColor = _h === void 0 ? '#000' : _h; var canvasRef = useRef(null); useEffect(function () { var drawGrids = function (canvas) { var canvasElm = canvasRef.current; // fix pixel var r = window.devicePixelRatio || 1; canvasElm.width *= r; canvasElm.height *= r; var ctx = canvas.getContext('2d'); ctx.scale(r, r); ctx.translate(0.5, 0.5); // setup step var k = Object.keys(data); var v = Object.values(data); var max = Math.max.apply(Math, v); var min = Math.min.apply(Math, v); var xStep = canvasElm.width / (k.length * r); var yStep = canvasElm.height / (max - min) * 0.5; // start point (x, y) var x = padding[0]; var y = canvasElm.height - (v[0] - min) * yStep - padding[1]; ctx.moveTo(x, y); for (var i = 0; i < k.length; i++) { ctx.lineWidth = labelSize; ctx.strokeStyle = labelColor; ctx.strokeText(customLabel(v[i]), x + labelPadding[0], y + labelPadding[1]); ctx.lineWidth = lineWidth; ctx.strokeStyle = lineColor; ctx.lineTo(x, y); x += xStep; y = canvasElm.height - (v[i + 1] - min) * yStep - padding[1]; } ctx.stroke(); canvasElm.style.zoom = "" + 1 / r; }; if (canvasRef.current !== null) { drawGrids(canvasRef.current); } }, [data, width, height, padding, lineColor, lineWidth, labelColor, labelPadding, labelSize, customLabel ]); return (React.createElement(LineChartWrapper, null, React.createElement("canvas", { ref: canvasRef, height: height, width: width }, React.createElement("p", null, "Your Browser Does Not Support Canvas")))); } var templateObject_1$1; var WeatherHourlyWrapper = styled.div(templateObject_1$2 || (templateObject_1$2 = __makeTemplateObject(["\n width: ", ";\n display: flex;\n justify-content: space-between;\n flex-direction: column;\n"], ["\n width: ", ";\n display: flex;\n justify-content: space-between;\n flex-direction: column;\n"])), function (props) { return props.theme.width; }); var WeatherHourlySection = styled.div(templateObject_2$1 || (templateObject_2$1 = __makeTemplateObject(["\n width: ", ";\n height: 50px;\n display: flex;\n justify-content: space-between;\n h2 {\n margin: 0;\n font-size: ", ";\n color: ", ";\n }\n"], ["\n width: ", ";\n height: 50px;\n display: flex;\n justify-content: space-between;\n h2 {\n margin: 0;\n font-size: ", ";\n color: ", ";\n }\n"])), function (props) { return props.theme.width; }, function (props) { return props.theme.mainFontSize; }, function (props) { return props.theme.mainFontColor; }); var HourlyCard = styled.div(templateObject_3$1 || (templateObject_3$1 = __makeTemplateObject(["\n width: 100px;\n align-items: center;\n display: flex;\n flex-direction: column;\n"], ["\n width: 100px;\n align-items: center;\n display: flex;\n flex-direction: column;\n"]))); function WeatherHourly(_a) { var hourly = _a.hourly, _b = _a.from, from = _b === void 0 ? 1 : _b, _c = _a.to, to = _c === void 0 ? 6 : _c, theme = _a.theme; var hourlyData = hourly.slice(from, to); return (React.createElement(WeatherHourlyWrapper, null, React.createElement(WeatherHourlySection, null, hourlyData.map(function (hourData) { return React.createElement(HourlyCard, { key: hourData.dt }, React.createElement("h2", null, new Date(hourData.dt * 1000).getHours(), ":00")); })), React.createElement(LineChart, { data: getHourlyData(hourly, from, to), height: theme.lineChartHeight, width: theme.width, lineColor: theme.lineChartColor, labelColor: theme.lineChartLabelColor, labelPadding: theme.lineChartLabelPadding, labelSize: theme.lineChartLabelSize, padding: theme.lineChartPadding }), React.createElement(WeatherHourlySection, null, hourlyData.map(function (hourData) { return React.createElement(HourlyCard, { key: hourData.dt }, React.createElement("img", { src: ICON_BASE_URL + hourData.weather[0].icon + ".png", alt: 'weather-info' })); })))); } var templateObject_1$2, templateObject_2$1, templateObject_3$1; var WeatherDailyWrapper = styled.div(templateObject_1$3 || (templateObject_1$3 = __makeTemplateObject(["\n width: ", ";\n display: flex;\n justify-content: space-between;\n font-size: ", ";\n color: ", ";\n h2 {\n margin: 0;\n font-size: ", ";\n }\n"], ["\n width: ", ";\n display: flex;\n justify-content: space-between;\n font-size: ", ";\n color: ", ";\n h2 {\n margin: 0;\n font-size: ", ";\n }\n"])), function (props) { return props.theme.width; }, function (props) { return props.theme.subFontSize; }, function (props) { return props.theme.subFontColor; }, function (props) { return props.theme.mainFontSize; }); var DailyCard = styled.div(templateObject_2$2 || (templateObject_2$2 = __makeTemplateObject(["\n width: 100px;\n align-items: center;\n display: flex;\n flex-direction: column;\n"], ["\n width: 100px;\n align-items: center;\n display: flex;\n flex-direction: column;\n"]))); var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; function WeatherDaily(_a) { var daily = _a.daily, _b = _a.from, from = _b === void 0 ? 1 : _b, _c = _a.to, to = _c === void 0 ? 6 : _c; var dailyData = daily.slice(from, to); return (React.createElement(WeatherDailyWrapper, null, dailyData.map(function (dayData) { return React.createElement(DailyCard, { key: dayData.dt }, React.createElement("h2", null, days[new Date(dayData.dt * 1000).getDay()]), React.createElement("img", { src: ICON_BASE_URL + dayData.weather[0].icon + ".png", alt: 'weather-info' }), React.createElement("p", null, Math.round(dayData.temp.max), " - ", Math.round(dayData.temp.min), "\u00B0C"), React.createElement("span", { role: "img", "aria-label": "drop" }, "\uD83D\uDCA7 "), React.createElement("p", null, dayData.humidity, "%")); }))); } var templateObject_1$3, templateObject_2$2; var WeatherWrapper = styled.div(templateObject_1$4 || (templateObject_1$4 = __makeTemplateObject(["\n background-color: ", ";\n background-image: linear-gradient(\n 19deg, \n ", " 0%, \n ", " 99%\n );\n width: ", ";\n height: ", ";\n border-radius: 4%;\n flex-direction: column;\n align-items: center;\n display: flex;\n top: 3vh;\n position: relative;\n"], ["\n background-color: ", ";\n background-image: linear-gradient(\n 19deg, \n ", " 0%, \n ", " 99%\n );\n width: ", ";\n height: ", ";\n border-radius: 4%;\n flex-direction: column;\n align-items: center;\n display: flex;\n top: 3vh;\n position: relative;\n"])), function (props) { return props.theme.color[0]; }, function (props) { return props.theme.color[0]; }, function (props) { return props.theme.color[1]; }, function (props) { return props.theme.width; }, function (props) { return props.theme.height; }); var Hr = styled.div(templateObject_2$3 || (templateObject_2$3 = __makeTemplateObject(["\n width: 90%;\n height: 0;\n border-bottom: solid 1px ", ";\n opacity: 0.4;\n margin: 10px 0;\n"], ["\n width: 90%;\n height: 0;\n border-bottom: solid 1px ", ";\n opacity: 0.4;\n margin: 10px 0;\n"])), function (props) { return props.theme.hrColor; }); function WeatherWidget(_a) { var apiKey = _a.apiKey, _b = _a.geo, geo = _b === void 0 ? undefined : _b, theme = _a.theme, _c = _a.exclude, exclude = _c === void 0 ? null : _c, _d = _a.dayRange, dayRange = _d === void 0 ? [1, 6] : _d, _e = _a.hourRange, hourRange = _e === void 0 ? [1, 6] : _e, className = _a.className, children = _a.children; var _f = useFetchWeather(apiKey, 'metric', exclude, geo), errorMsg = _f[0], loadingMsg = _f[1], weatherData = _f[2]; var assignedTheme; if (theme) { assignedTheme = __assign(__assign({}, defaultTheme), theme); } else { assignedTheme = defaultTheme; } var renderWediget = function () { if (loadingMsg) { return (React.createElement("p", { style: { color: theme === null || theme === void 0 ? void 0 : theme.mainFontColor, fontSize: '30px', marginTop: '50%' } }, loadingMsg)); } if (errorMsg) { return (React.createElement("p", { style: { color: theme === null || theme === void 0 ? void 0 : theme.mainFontColor, fontSize: '30px', marginTop: '50%' } }, errorMsg)); } return (React.createElement(React.Fragment, null, React.createElement(WeatherHeader, { today: weatherData.daily[0], current: weatherData.current, timezone: weatherData.timezone }), React.createElement(Hr, { theme: theme }), React.createElement(WeatherHourly, { hourly: weatherData.hourly, theme: assignedTheme, from: hourRange[0], to: hourRange[1] }), React.createElement(Hr, { theme: theme }), React.createElement(WeatherDaily, { daily: weatherData.daily, from: dayRange[0], to: dayRange[1] }))); }; return (React.createElement(ThemeProvider, { theme: assignedTheme }, React.createElement(WeatherWrapper, { className: className }, renderWediget()), children)); } var templateObject_1$4, templateObject_2$3; export default WeatherWidget; export { LineChart, WeatherDaily, WeatherHeader, WeatherHourly, dayTheme, defaultTheme, nightTheme, useFetchWeather, useGeolocation as useGeoLocation };