From 389edb7a6a3c4e62c6aa6d6b031eaec955398af8 Mon Sep 17 00:00:00 2001 From: Jennifer Kirsch Date: Tue, 25 Jan 2022 10:28:50 +0100 Subject: [PATCH 1/3] Add a sidebar with POI info --- assets/js/Root.js | 2 +- assets/js/components/ButterflyMap.js | 126 ++++++++++---- assets/js/components/OpenHours.js | 60 +++---- assets/js/components/PointBar.js | 45 +---- assets/js/components/PointCard.js | 64 +++---- assets/js/components/Sidebar.js | 89 ++++++++++ assets/js/data/helpers.js | 17 ++ assets/js/data/propTypes.js | 1 + package-lock.json | 242 ++++++++++++++------------- 9 files changed, 390 insertions(+), 256 deletions(-) create mode 100644 assets/js/components/Sidebar.js diff --git a/assets/js/Root.js b/assets/js/Root.js index f929100..efcd87f 100644 --- a/assets/js/Root.js +++ b/assets/js/Root.js @@ -47,7 +47,7 @@ const Root = () => { banana: true, hours: { sunday: [{from: ['7', '0'], until: ['22', '0']}], - monday: [{from: ['7', '0'], until: ['22', '0']}], + monday: [{from: ['7', '0'], until: ['15', '0']}], tuesday: [{from: ['20', '0'], until: ['22', '0']}], wednesday: [{from: ['7', '0'], until: ['22', '0']}], thursday: [{from: ['7', '0'], until: ['22', '0']}], diff --git a/assets/js/components/ButterflyMap.js b/assets/js/components/ButterflyMap.js index ff4fe3b..b2fedbc 100644 --- a/assets/js/components/ButterflyMap.js +++ b/assets/js/components/ButterflyMap.js @@ -1,3 +1,6 @@ +import ownCss from '../../css/ButterflyMap.css'; // NOT unused. +import css from 'maplibre-gl/dist/maplibre-gl.css'; // NOT unused either. + import PropTypes from 'prop-types'; import React from 'react'; import Button from './Button'; @@ -5,11 +8,9 @@ import ControlBar from './ControlBar'; import PointBar from './PointBar'; import styled, {ThemeProvider} from 'styled-components'; import ReactMapGL, {AttributionControl, FlyToInterpolator, Marker} from 'react-map-gl'; -import {localStringsPropTypes, dayPropTypes, hoursPropTypes} from '../data/propTypes'; +import {localStringsPropTypes, hoursPropTypes} from '../data/propTypes'; import {filterHours} from '../data/helpers'; - -import ownCss from '../../css/ButterflyMap.css'; // NOT unused. -import css from 'maplibre-gl/dist/maplibre-gl.css'; // NOT unused either. +import {MapSidebar, SidebarContent} from './Sidebar'; const PointerBox = styled.div` cursor: pointer; @@ -19,15 +20,24 @@ const CenterMapButton = styled(Button)` margin: 0.5rem 0 0.5rem 0; `; +const MapAndBarContainer = styled.div` + display: flex; +`; + +const MapContainer = styled.div` + width: 100%; + z-index: 0; +`; + const Markers = React.memo((props) => { // Use memo to avoid needless re-renders of the markers - const {displayPointTypes, doMapMove} = props; + const {displayPointTypes, handleMapMarkerClick} = props; return <> {displayPointTypes.map((pointType) => { return pointType.points.map((point, index) => doMapMove(point.position)} + onClick={() => handleMapMarkerClick(point.position)} id={'react-butterfly-map-pointer' + pointType.name + index} getCursor={() => 'pointer'} > @@ -42,10 +52,14 @@ const Markers = React.memo((props) => { }); Markers.propTypes = { - doMapMove: PropTypes.func.isRequired, + handleMapMarkerClick: PropTypes.func.isRequired, displayPointTypes: PropTypes.array.isRequired, }; +const calculateDistance = (position, to) => { + return Math.abs(position.latitude - to.latitude) + Math.abs(position.longitude - to.longitude); +}; + export const ButterflyMap = (props) => { const {customFilters} = props; const [position, setPosition] = React.useState(props.center); @@ -58,8 +72,8 @@ export const ButterflyMap = (props) => { const [typeOptions, setTypeOptions] = React.useState([]); const [showAllTypes, setShowAllTypes] = React.useState(() => { if (customFilters) { - for (const customFilter of customFilters){ - if (customFilter.defaultValue === false){ + for (const customFilter of customFilters) { + if (customFilter.defaultValue === false) { return false; } } @@ -68,21 +82,46 @@ export const ButterflyMap = (props) => { }); const [showClosedRightNow, setShowClosedRightNow] = React.useState(true); const [displayPointTypes, setDisplayPointTypes] = React.useState([]); + const [displayPoints, setDisplayPoints] = React.useState([]); const [userPosition, setUserPosition] = React.useState(null); const [centerMapDisabled, setCenterMapDisabled] = React.useState(true); const [paginationPage, setPaginationPage] = React.useState(1); const [hideMap, setHideMap] = React.useState(false); - const [hoursSet, setHoursSet] = React.useState(() => { + const [sidebarShowing, setSidebarShowing] = React.useState(false); + const [customFilterValues, setCustomFilterValues] = React.useState(customFilters ? customFilters.map((customFilter) => customFilter.defaultValue) : []); + const [hoursSet] = React.useState(() => { for (const pointType of props.pointTypes) { - for (const point of pointType.points){ - if (point.hours){ + for (const point of pointType.points) { + if (point.hours) { return true; } } } return false; }); - const [customFilterValues, setCustomFilterValues] = React.useState(customFilters ? customFilters.map((customFilter) => customFilter.defaultValue) : []); + const [viewport, setViewport] = React.useState({ + ...props.center, + zoom: props.zoom ?? 8, + width: 'fit', + height: props.height, + }); + + React.useEffect(() => { + const newPoints = []; + displayPointTypes.map((pointType) => { + pointType.points.map((point, index) => { + newPoints.push({...point, type: pointType.name, index: index}); + }); + }); + + if (newPoints.length !== displayPoints.length) { + setPaginationPage(1); + } + + setDisplayPoints(newPoints.sort((a, b) => { + return calculateDistance(position, a.position) - calculateDistance(position, b.position); + })); + }, [displayPointTypes, position]); const updateCustomFilterValue = (index, newVal) => { const newCustomFilterValues = [...customFilterValues]; @@ -97,13 +136,6 @@ export const ButterflyMap = (props) => { updateDisplayPointTypes(props.pointTypes, false, showClosedRightNow, newCustomFilterValues); }; - const [viewport, setViewport] = React.useState({ - ...props.center, - zoom: props.zoom ?? 8, - width: 'fit', - height: props.height, - }); - const theme = { reduceMotion: reduceMotion, error: props.theme?.error ?? 'red', @@ -116,8 +148,23 @@ export const ButterflyMap = (props) => { popupBackgroundColor: props.theme?.popupBackgroundColor ?? 'white', highlightOptionColor: props.theme?.highlightOptionColor ?? 'lightgray', typePopupMinWidth: props.theme?.typePopupMinWidth ?? '15rem', + backgroundColor: props.theme?.backgroundColor ?? '#fff', }; + const handlePointBarMarkerClick = (e, point) => { + moveMapPosition(e, point.position); + + // Browsers have issues rendering too many animations at once, resulting in a buggy sidebar entry animation + // if it's triggered at the same time as the map is moved. + // To avoid that we wait for 50ms before showing the sidebar. + window.setTimeout(() => setSidebarShowing(true), 50); + }; + + const handleMapMarkerClick = (position) => { + doMapMove(position); + window.setTimeout(() => setSidebarShowing(true), 50); + } + const updateDisplayPointTypes = (proposedTypes, updateTypeOptions = false, showClosed = showClosedRightNow, currentCustomFilterValues = customFilterValues) => { const newTypeOptions = []; const newDisplayPointTypes = []; @@ -347,25 +394,33 @@ export const ButterflyMap = (props) => { customFilterValues={customFilterValues} updateCustomFilterValue={updateCustomFilterValue} /> - {!hideMap && <> - setViewport(newViewport)} - mapStyle={props.tileServer}> - - - - - {props.localStrings?.centerMap ?? 'Center map on current location'} - - } + {!hideMap && + + {displayPoints.length > 0 && + } + + + setViewport(newViewport)} + mapStyle={props.tileServer}> + + + + + {props.localStrings?.centerMap ?? 'Center map on current location'} + + + } {typeOptions.length > 0 && - } ; }; @@ -416,5 +471,6 @@ ButterflyMap.propTypes = { popupBackgroundColor: PropTypes.string, highlightOptionColor: PropTypes.string, typePopupMinWidth: PropTypes.string, + backgroundColor: PropTypes.string, }), }; diff --git a/assets/js/components/OpenHours.js b/assets/js/components/OpenHours.js index caa43be..2602fb5 100644 --- a/assets/js/components/OpenHours.js +++ b/assets/js/components/OpenHours.js @@ -91,11 +91,11 @@ const HoursRow = (props) => { return {title} {typeof dayHours === 'boolean' - ? dayHours === true ? {localStrings?.allDay ?? 'All day'} : - {localStrings?.closed ?? 'Closed'} + ? dayHours === true ? {localStrings?.allDay ?? 'All day'} : + {localStrings?.closed ?? 'Closed'} : <> {!!closed - ? + ? : @@ -131,42 +131,32 @@ const OpenHours = (props) => { const hour = now.getHours(); const minutes = now.getMinutes(); - if (displayMore) { - return <> - - - {Object.entries(hours).map(([day, dayHours], index) => { + return <> + + + {displayMore + ? Object.entries(hours).map(([day, dayHours], index) => { if (typeof dayHours === 'object' || typeof dayHours === 'boolean') { return ; } - })} - - - - {!!hours.text && {hours.text}} - setDisplayMore(false)}> - {localStrings?.showLess ?? 'Show less'} - - ; - } else { - return <> - - - - - - - - setDisplayMore(true)}> - {localStrings?.showMore ?? 'Show more'} - - ; - } + }) + : <> + + + } + + + + {!!hours.text && {hours.text}} + setDisplayMore(!displayMore)}> + {displayMore ? localStrings?.showLess ?? 'Show less' : localStrings?.showMore ?? 'Show more'} + + ; }; // Hours has to be an array with the index 0 containing hours for sunday and counting up from there. diff --git a/assets/js/components/PointBar.js b/assets/js/components/PointBar.js index 29125b9..922f165 100644 --- a/assets/js/components/PointBar.js +++ b/assets/js/components/PointBar.js @@ -16,43 +16,17 @@ const CardContainer = styled.div` `; const PointBar = (props) => { - const [points, setPoints] = React.useState([]); const [entriesPerPage, _setEntriesPerPage] = React.useState(window.innerWidth < 1000 ? 4 : 8); - const {pointTypes, moveMapPosition, position, page, setPage} = props; + const {page, setPage, displayPoints, userPosition, localStrings, handlePointBarMarkerClick} = props; const setEntriesPerPage = (newEntriesPerPage) => { _setEntriesPerPage(newEntriesPerPage); setPage(1); } - const handleSidebarMarkerClick = (e, point) => { - moveMapPosition(e, point.position); - }; - - const calculateDistance = (to) => { - return Math.abs(position.latitude - to.latitude) + Math.abs(position.longitude - to.longitude); - }; - - React.useEffect(() => { - const newPoints = []; - pointTypes.map((pointType) => { - pointType.points.map((point, index) => { - newPoints.push({...point, type: pointType.name, index: index}); - }); - }); - - if (newPoints.length !== points.length) { - setPage(1); - } - - setPoints(newPoints.sort((a, b) => { - return calculateDistance(a.position) - calculateDistance(b.position); - })); - }, [pointTypes, position]); - let paginatedPoints = []; for (let c = 0; c < entriesPerPage; c++) { - const point = points[entriesPerPage * (page - 1) + c]; + const point = displayPoints[entriesPerPage * (page - 1) + c]; if (point === undefined) { break; } @@ -65,9 +39,9 @@ const PointBar = (props) => { point={point} key={index} selected={page === 1 && index === 0} - handleSidebarMarkerClick={handleSidebarMarkerClick} - userPosition={props.userPosition} - localStrings={props.localStrings} + handlePointBarMarkerClick={handlePointBarMarkerClick} + userPosition={userPosition} + localStrings={localStrings} />, )} @@ -75,18 +49,17 @@ const PointBar = (props) => { setPage={setPage} entriesPerPage={entriesPerPage} setEntriesPerPage={setEntriesPerPage} - entryCount={points.length} - localStrings={props.localStrings} + entryCount={displayPoints.length} + localStrings={localStrings} /> ; }; PointBar.propTypes = { - pointTypes: PropTypes.array.isRequired, // TODO: arrayOf shape - moveMapPosition: PropTypes.func.isRequired, - position: PropTypes.shape({latitude: PropTypes.number, longitude: PropTypes.number}).isRequired, + displayPoints: PropTypes.array.isRequired, page: PropTypes.number.isRequired, setPage: PropTypes.func.isRequired, + handlePointBarMarkerClick: PropTypes.func.isRequired, userPosition: PropTypes.shape({latitude: PropTypes.number, longitude: PropTypes.number}), localStrings: PropTypes.shape(localStringsPropTypes), }; diff --git a/assets/js/components/PointCard.js b/assets/js/components/PointCard.js index 7d229f8..9917e67 100644 --- a/assets/js/components/PointCard.js +++ b/assets/js/components/PointCard.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; -import {weekdays} from '../data/helpers'; +import {checkPointHours} from '../data/helpers'; import {localStringsPropTypes} from '../data/propTypes'; import {Card, CardContent} from './Card'; import OpenHours from './OpenHours'; @@ -18,48 +18,50 @@ const Link = styled.a` font-size: 1.2rem !important; `; +const Heading = styled.p` + font-size: 1.2rem; +` + const SmallLink = styled(Link)` line-height: 0.8rem; font-size: 0.8rem !important; margin-bottom: 0.25rem; `; -const checkPointHours = (point) => { - if (point.hasHours) { - return true; - } +export const PointCardContent = (props) => { + const {point, localStrings, handlePointBarMarkerClick, userPosition, headingIsNoLink} = props; + + return <> + {headingIsNoLink + ? {point.text ? point.text : point.address} + : handlePointBarMarkerClick(e, point)}> + {point.text ? point.text : point.address} + } - const pointHours = point.hours; - if (pointHours) { - for (const index of weekdays) { - if (pointHours[index]) { - point.hasHours = true; - return true; - } - } - } - return false; + {!!point.address && !!point.text && {point.address}} + {!!point.additionalInfo && {point.additionalInfo}} + {!!point.website && {props.localStrings?.website ?? 'Website'}} + + {props.localStrings?.directions ?? 'Directions (Google Maps)'} + + {point.type} + {checkPointHours(point) && + } + ; }; const PointCard = (props) => { - const {point, handleSidebarMarkerClick, selected} = props; + const {point, handlePointBarMarkerClick, selected, localStrings, userPosition} = props; return - handleSidebarMarkerClick(e, point)}> - {point.text ? point.text : point.address} - - {!!point.address && !!point.text && {point.address}} - {!!point.additionalInfo && {point.additionalInfo}} - {!!point.website && {props.localStrings?.website ?? 'Website'}} - - {props.localStrings?.directions ?? 'Directions (Google Maps)'} - - {point.type} - {checkPointHours(point) && - } + ; }; @@ -67,7 +69,7 @@ const PointCard = (props) => { PointCard.propTypes = { point: PropTypes.object.isRequired, // TODO: shape selected: PropTypes.bool.isRequired, - handleSidebarMarkerClick: PropTypes.func.isRequired, + handlePointBarMarkerClick: PropTypes.func.isRequired, userPosition: PropTypes.object, // TODO: shape localStrings: PropTypes.shape(localStringsPropTypes), }; diff --git a/assets/js/components/Sidebar.js b/assets/js/components/Sidebar.js new file mode 100644 index 0000000..36c29f4 --- /dev/null +++ b/assets/js/components/Sidebar.js @@ -0,0 +1,89 @@ +import React from 'react'; +import styled from 'styled-components'; +import {checkPointHours} from '../data/helpers'; +import Button from './Button'; +import OpenHours from './OpenHours'; + + +export const MapSidebar = styled.div` + width: 1px; + transition: width ${props => props.theme.reduceMotion ? '0s' : '0.5s'} ease-out; + overflow: hidden; + z-index: 10; + position: absolute; + height: ${props => props.height}px; + background-color: ${props => props.theme.backgroundColor}; + box-sizing: border-box; + overflow-wrap: anywhere; + + & > div { + margin: 1rem; + height: 95%; + overflow: auto; + } + + & > div > *, & > div > table tbody tr td.special-day, & > div > div > button { + transition: ${props => props.theme.reduceMotion ? '0s' : 'color 0s 0.5s, border 0s 0.5s'}; + } + + &[data-showing=true] { + width: 20%; + } + + &[data-showing=false] > div > *, &[data-showing=false] > div > table tbody tr td.special-day, &[data-showing=false] > div > div > button { + color: ${props => props.theme.backgroundColor} !important; + border: none; + transition: color 0s 0s, border 0s 0s; + } + + &[data-showing=false] > div { + overflow: hidden; + } +`; + +const SidebarHeading = styled.p` + /* TODO: h? */ + font-size: 1.2rem; + margin: 0.5rem 0 0.5rem 0; +`; + +const HeadingLink = styled.a` + display: block; + margin: 0.25rem 0 0.25rem 0; +`; + +const SidebarType = styled.span` + margin: 0.25rem 0 0.25rem 0; + display: block; +`; + +const SidebarButtonContainer = styled.div` + display: flex; + width: 100%; +`; + +const CloseSidebarButton = styled(Button)` + margin-left: auto; +`; + +export const SidebarContent = (props) => { + const {point, userPosition, localStrings, setSidebarShowing} = props; + + return
+ + setSidebarShowing(false)}>{localStrings?.hide_sidebar ?? 'Hide Sidebar'} × + + {point.text ? point.text : point.address} + {!!point.address && !!point.text && {point.address}} + {!!point.additionalInfo && {point.additionalInfo}} + {!!point.website && {props.localStrings?.website ?? 'Website'}} + + {props.localStrings?.directions ?? 'Directions (Google Maps)'} + + {point.type} + {checkPointHours(point) && + } +
; +}; diff --git a/assets/js/data/helpers.js b/assets/js/data/helpers.js index 761a984..0704643 100644 --- a/assets/js/data/helpers.js +++ b/assets/js/data/helpers.js @@ -17,3 +17,20 @@ export const filterHours = (point, currentDay, currentHour, currentMinute) => { } return false; }; + +export const checkPointHours = (point) => { + if (point.hasHours) { + return true; + } + + const pointHours = point.hours; + if (pointHours) { + for (const index of weekdays) { + if (pointHours[index]) { + point.hasHours = true; + return true; + } + } + } + return false; +}; diff --git a/assets/js/data/propTypes.js b/assets/js/data/propTypes.js index f6d401f..7956521 100644 --- a/assets/js/data/propTypes.js +++ b/assets/js/data/propTypes.js @@ -36,6 +36,7 @@ export const localStringsPropTypes = { hideMap: PropTypes.string.isRequired, typesSubMenu: PropTypes.string.isRequired, filterSubMenu: PropTypes.string.isRequired, + hide_sidebar: PropTypes.string.isRequired, }; export const dayPropTypes = PropTypes.oneOfType( diff --git a/package-lock.json b/package-lock.json index 5aa7aa1..616d493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,20 +60,20 @@ } }, "node_modules/@babel/core": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", - "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", + "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.7", + "@babel/generator": "^7.16.8", "@babel/helper-compilation-targets": "^7.16.7", "@babel/helper-module-transforms": "^7.16.7", "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.7", + "@babel/parser": "^7.16.12", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7", + "@babel/traverse": "^7.16.10", + "@babel/types": "^7.16.8", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -145,9 +145,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", - "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.10.tgz", + "integrity": "sha512-wDeej0pu3WN/ffTxMNCPW5UCiOav8IcLRxSIyp/9+IF2xJUM9h/OYjg0IJLHaL6F8oU8kqMz9nc1vryXhMsgXg==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", @@ -433,9 +433,9 @@ } }, "node_modules/@babel/highlight": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", - "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", @@ -446,9 +446,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", - "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==", + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz", + "integrity": "sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==", "bin": { "parser": "bin/babel-parser.js" }, @@ -687,12 +687,12 @@ } }, "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz", - "integrity": "sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.10", "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { @@ -1423,9 +1423,9 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.8.tgz", - "integrity": "sha512-6Kg2XHPFnIarNweZxmzbgYnnWsXxkx9WQUVk2sksBRL80lBC1RAQV3wQagWxdCHiYHqPN+oenwNIuttlYgIbQQ==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.10.tgz", + "integrity": "sha512-9nwTiqETv2G7xI4RvXHNfpGdr8pAA+Q/YtN3yLK7OoK7n9OibVm/xymJ838a9A6E/IciOLPj82lZk0fW6O4O7w==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.16.7", @@ -1567,9 +1567,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.8.tgz", - "integrity": "sha512-9rNKgVCdwHb3z1IlbMyft6yIXIeP3xz6vWvGaLHrJThuEIqWfHb0DNBH9VuTgnDfdbUDhkmkvMZS/YMCtP7Elg==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", + "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", "dev": true, "dependencies": { "@babel/compat-data": "^7.16.8", @@ -1590,7 +1590,7 @@ "@babel/plugin-proposal-object-rest-spread": "^7.16.7", "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", "@babel/plugin-proposal-private-property-in-object": "^7.16.7", "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -1732,9 +1732,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz", - "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz", + "integrity": "sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==", "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.16.8", @@ -1742,7 +1742,7 @@ "@babel/helper-function-name": "^7.16.7", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.16.8", + "@babel/parser": "^7.16.10", "@babel/types": "^7.16.8", "debug": "^4.1.0", "globals": "^11.1.0" @@ -2305,9 +2305,9 @@ } }, "node_modules/@types/node": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.9.tgz", - "integrity": "sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ==", + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz", + "integrity": "sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog==", "dev": true }, "node_modules/@types/parse-json": { @@ -2821,9 +2821,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001300", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz", - "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==", + "version": "1.0.30001301", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz", + "integrity": "sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA==", "dev": true, "funding": { "type": "opencollective", @@ -2844,10 +2844,16 @@ } }, "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -3677,9 +3683,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.46", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.46.tgz", - "integrity": "sha512-UtV0xUA/dibCKKP2JMxOpDtXR74zABevuUEH4K0tvduFSIoxRVcYmQsbB51kXsFTX8MmOyWMt8tuZAlmDOqkrQ==", + "version": "1.4.51", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.51.tgz", + "integrity": "sha512-JNEmcYl3mk1tGQmy0EvL5eik/CKSBuzAyGP0QFdG6LIgxQe3II0BL1m2zKc2MZMf3uGqHWE1TFddJML0RpjSHQ==", "dev": true }, "node_modules/emoji-regex": { @@ -7094,9 +7100,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -7665,12 +7671,12 @@ "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" }, "node_modules/resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "dependencies": { - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -7739,9 +7745,9 @@ "dev": true }, "node_modules/rollup": { - "version": "2.64.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.64.0.tgz", - "integrity": "sha512-+c+lbw1lexBKSMb1yxGDVfJ+vchJH3qLbmavR+awDinTDA2C5Ug9u7lkOzj62SCu0PKUExsW36tpgW7Fmpn3yQ==", + "version": "2.66.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.66.0.tgz", + "integrity": "sha512-L6mKOkdyP8HK5kKJXaiWG7KZDumPJjuo1P+cfyHOJPNNTK3Moe7zCH5+fy7v8pVmHXtlxorzaBjvkBMB23s98g==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -7986,9 +7992,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.48.0.tgz", - "integrity": "sha512-hQi5g4DcfjcipotoHZ80l7GNJHGqQS5LwMBjVYB/TaT0vcSSpbgM8Ad7cgfsB2M0MinbkEQQPO9+sjjSiwxqmw==", + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", + "integrity": "sha512-TVwVdNDj6p6b4QymJtNtRS2YtLJ/CqZriGg0eIAbAKMlN8Xy6kbv33FsEZSF7FufFFM705SQviHjjThfaQ4VNw==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -8400,9 +8406,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, "engines": { "node": ">=0.10.0" @@ -9263,20 +9269,20 @@ "dev": true }, "@babel/core": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", - "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", + "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.7", + "@babel/generator": "^7.16.8", "@babel/helper-compilation-targets": "^7.16.7", "@babel/helper-module-transforms": "^7.16.7", "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.7", + "@babel/parser": "^7.16.12", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7", + "@babel/traverse": "^7.16.10", + "@babel/types": "^7.16.8", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -9326,9 +9332,9 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz", - "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.10.tgz", + "integrity": "sha512-wDeej0pu3WN/ffTxMNCPW5UCiOav8IcLRxSIyp/9+IF2xJUM9h/OYjg0IJLHaL6F8oU8kqMz9nc1vryXhMsgXg==", "dev": true, "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", @@ -9542,9 +9548,9 @@ } }, "@babel/highlight": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", - "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", "requires": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", @@ -9552,9 +9558,9 @@ } }, "@babel/parser": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", - "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==" + "version": "7.16.12", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz", + "integrity": "sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.16.7", @@ -9703,12 +9709,12 @@ } }, "@babel/plugin-proposal-private-methods": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz", - "integrity": "sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", + "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", + "@babel/helper-create-class-features-plugin": "^7.16.10", "@babel/helper-plugin-utils": "^7.16.7" } }, @@ -10178,9 +10184,9 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.8.tgz", - "integrity": "sha512-6Kg2XHPFnIarNweZxmzbgYnnWsXxkx9WQUVk2sksBRL80lBC1RAQV3wQagWxdCHiYHqPN+oenwNIuttlYgIbQQ==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.10.tgz", + "integrity": "sha512-9nwTiqETv2G7xI4RvXHNfpGdr8pAA+Q/YtN3yLK7OoK7n9OibVm/xymJ838a9A6E/IciOLPj82lZk0fW6O4O7w==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.16.7", @@ -10268,9 +10274,9 @@ } }, "@babel/preset-env": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.8.tgz", - "integrity": "sha512-9rNKgVCdwHb3z1IlbMyft6yIXIeP3xz6vWvGaLHrJThuEIqWfHb0DNBH9VuTgnDfdbUDhkmkvMZS/YMCtP7Elg==", + "version": "7.16.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", + "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", "dev": true, "requires": { "@babel/compat-data": "^7.16.8", @@ -10291,7 +10297,7 @@ "@babel/plugin-proposal-object-rest-spread": "^7.16.7", "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.7", + "@babel/plugin-proposal-private-methods": "^7.16.11", "@babel/plugin-proposal-private-property-in-object": "^7.16.7", "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -10406,9 +10412,9 @@ } }, "@babel/traverse": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz", - "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==", + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz", + "integrity": "sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw==", "requires": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.16.8", @@ -10416,7 +10422,7 @@ "@babel/helper-function-name": "^7.16.7", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.16.8", + "@babel/parser": "^7.16.10", "@babel/types": "^7.16.8", "debug": "^4.1.0", "globals": "^11.1.0" @@ -10792,9 +10798,9 @@ } }, "@types/node": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.9.tgz", - "integrity": "sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ==", + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.10.tgz", + "integrity": "sha512-S/3xB4KzyFxYGCppyDt68yzBU9ysL88lSdIah4D6cptdcltc4NCPCAMc0+PCpg/lLIyC7IPvj2Z52OJWeIUkog==", "dev": true }, "@types/parse-json": { @@ -11213,9 +11219,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001300", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz", - "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==", + "version": "1.0.30001301", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001301.tgz", + "integrity": "sha512-csfD/GpHMqgEL3V3uIgosvh+SVIQvCh43SNu9HRbP1lnxkKm1kjDG4f32PP571JplkLjfS+mg2p1gxR7MYrrIA==", "dev": true }, "chalk": { @@ -11229,9 +11235,9 @@ } }, "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "requires": { "anymatch": "~3.1.2", @@ -11885,9 +11891,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.4.46", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.46.tgz", - "integrity": "sha512-UtV0xUA/dibCKKP2JMxOpDtXR74zABevuUEH4K0tvduFSIoxRVcYmQsbB51kXsFTX8MmOyWMt8tuZAlmDOqkrQ==", + "version": "1.4.51", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.51.tgz", + "integrity": "sha512-JNEmcYl3mk1tGQmy0EvL5eik/CKSBuzAyGP0QFdG6LIgxQe3II0BL1m2zKc2MZMf3uGqHWE1TFddJML0RpjSHQ==", "dev": true }, "emoji-regex": { @@ -14504,9 +14510,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz", - "integrity": "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -14985,12 +14991,12 @@ "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" }, "resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -15049,9 +15055,9 @@ "dev": true }, "rollup": { - "version": "2.64.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.64.0.tgz", - "integrity": "sha512-+c+lbw1lexBKSMb1yxGDVfJ+vchJH3qLbmavR+awDinTDA2C5Ug9u7lkOzj62SCu0PKUExsW36tpgW7Fmpn3yQ==", + "version": "2.66.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.66.0.tgz", + "integrity": "sha512-L6mKOkdyP8HK5kKJXaiWG7KZDumPJjuo1P+cfyHOJPNNTK3Moe7zCH5+fy7v8pVmHXtlxorzaBjvkBMB23s98g==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -15249,9 +15255,9 @@ "dev": true }, "sass": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.48.0.tgz", - "integrity": "sha512-hQi5g4DcfjcipotoHZ80l7GNJHGqQS5LwMBjVYB/TaT0vcSSpbgM8Ad7cgfsB2M0MinbkEQQPO9+sjjSiwxqmw==", + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", + "integrity": "sha512-TVwVdNDj6p6b4QymJtNtRS2YtLJ/CqZriGg0eIAbAKMlN8Xy6kbv33FsEZSF7FufFFM705SQviHjjThfaQ4VNw==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -15630,9 +15636,9 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz", - "integrity": "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, "source-map-support": { From 3c5056cd3ec578ef3c50bfe11582cb97adcfb049 Mon Sep 17 00:00:00 2001 From: Jennifer Kirsch Date: Tue, 25 Jan 2022 10:30:40 +0100 Subject: [PATCH 2/3] Improve location consent handling --- assets/js/components/ButterflyMap.js | 56 ++++++++++++++++++++-------- assets/js/data/propTypes.js | 1 + 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/assets/js/components/ButterflyMap.js b/assets/js/components/ButterflyMap.js index b2fedbc..d97151d 100644 --- a/assets/js/components/ButterflyMap.js +++ b/assets/js/components/ButterflyMap.js @@ -84,6 +84,8 @@ export const ButterflyMap = (props) => { const [displayPointTypes, setDisplayPointTypes] = React.useState([]); const [displayPoints, setDisplayPoints] = React.useState([]); const [userPosition, setUserPosition] = React.useState(null); + const [positionRetry, setPositionRetry] = React.useState(false); + const [locationBlocked, setLocationBlocked] = React.useState(true); const [centerMapDisabled, setCenterMapDisabled] = React.useState(true); const [paginationPage, setPaginationPage] = React.useState(1); const [hideMap, setHideMap] = React.useState(false); @@ -163,7 +165,7 @@ export const ButterflyMap = (props) => { const handleMapMarkerClick = (position) => { doMapMove(position); window.setTimeout(() => setSidebarShowing(true), 50); - } + }; const updateDisplayPointTypes = (proposedTypes, updateTypeOptions = false, showClosed = showClosedRightNow, currentCustomFilterValues = customFilterValues) => { const newTypeOptions = []; @@ -336,25 +338,39 @@ export const ButterflyMap = (props) => { React.useEffect(() => { const updateUserPosition = () => { - try { - if (isSecureContext) { - if ('geolocation' in navigator) { - navigator.geolocation.getCurrentPosition((position) => { - setCenterMapDisabled(false); - setUserPosition({latitude: position.coords.latitude, longitude: position.coords.longitude}); - }); - return true; + if (window.localStorage.getItem('geolocationBlocked') !== 'true' && !locationBlocked) { + try { + if (isSecureContext) { + if ('geolocation' in navigator) { + navigator.geolocation.getCurrentPosition((position) => { + setCenterMapDisabled(false); + setLocationBlocked(false); + setUserPosition({latitude: position.coords.latitude, longitude: position.coords.longitude}); + }, () => { + window.localStorage.setItem('geolocationBlocked', 'true'); + setLocationBlocked(true); + }); + return true; + } else { + console.info('Geolocation permission not given or feature not available.'); + } } else { - console.info('Geolocation permission not given or feature not available.'); + console.info('Geolocation is only available in a secure context'); } - } else { - console.info('Geolocation is only available in a secure context'); + } catch { + console.debug('Could not get geolocation. Are you using a somewhat modern browser?'); } - } catch { - console.debug('Could not get geolocation. Are you using a somewhat modern browser?'); + } else { + setCenterMapDisabled(false); + setLocationBlocked(true); } + return false; }; + window.addEventListener('scroll', () => { + setLocationBlocked(false); + }, {once: true}) + let updateUserPositionInterval = false; if (updateUserPosition()) { updateUserPositionInterval = window.setInterval(updateUserPosition, 30000); @@ -365,11 +381,16 @@ export const ButterflyMap = (props) => { clearInterval(updateUserPositionInterval); } }; - }, []); + }, [positionRetry, locationBlocked]); const handleCenterMapClick = () => { + if (window.localStorage.getItem('geolocationBlocked') === 'true') { + window.localStorage.setItem('geolocationBlocked', 'false'); + } if (userPosition) { doMapMove(userPosition, false); + } else { + setPositionRetry(!positionRetry); } }; @@ -409,7 +430,10 @@ export const ButterflyMap = (props) => { - + {props.localStrings?.centerMap ?? 'Center map on current location'} diff --git a/assets/js/data/propTypes.js b/assets/js/data/propTypes.js index 7956521..ed194e9 100644 --- a/assets/js/data/propTypes.js +++ b/assets/js/data/propTypes.js @@ -37,6 +37,7 @@ export const localStringsPropTypes = { typesSubMenu: PropTypes.string.isRequired, filterSubMenu: PropTypes.string.isRequired, hide_sidebar: PropTypes.string.isRequired, + location_permission_needed: PropTypes.string.isRequired, }; export const dayPropTypes = PropTypes.oneOfType( From 38a7c431f609ddfc70ad52276eaa57d7e37e7c4e Mon Sep 17 00:00:00 2001 From: Jennifer Kirsch Date: Tue, 25 Jan 2022 11:12:54 +0100 Subject: [PATCH 3/3] 0.8.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 616d493..0c778d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "react-butterfly-map", - "version": "0.7.9", + "version": "0.8.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "react-butterfly-map", - "version": "0.7.9", + "version": "0.8.0", "license": "MIT", "dependencies": { "maplibre-gl": "^1.15.2", diff --git a/package.json b/package.json index 72f9b9f..8819219 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-butterfly-map", - "version": "0.7.9", + "version": "0.8.0", "license": "MIT", "private": false, "main": "dist/react-butterfly-map.min.js",