diff --git a/package.json b/package.json index 3d6bd44..723d614 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "js-yaml": "^3.13.1", "leaflet": "^1.0.3", "marked": "^0.7.0", + "moment": "^2.26.0", "normalizr": "^3.2.3", "npm-check-updates": "^3.1.20", "object-hash": "^1.3.0", diff --git a/src/common/utilities.js b/src/common/utilities.js index cd646f6..d32e343 100644 --- a/src/common/utilities.js +++ b/src/common/utilities.js @@ -1,5 +1,17 @@ import { timeFormat, timeParse } from 'd3' +import moment from 'moment' + +let { DATE_FMT, TIME_FMT } = process.env +if (!DATE_FMT) DATE_FMT = 'MM/DD/YYYY' +if (!TIME_FMT) TIME_FMT = 'HH:mm' + +export function calcDatetime (date, time) { + if (!time) time = '00:00' + const dt = moment(`${date} ${time}`, `${DATE_FMT} ${TIME_FMT}`) + return dt.toDate() +} + /** * Get URI params to start with predefined set of * https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript @@ -39,10 +51,9 @@ export function isNotNullNorUndefined (variable) { } /* -* Capitalizes _only_ the first letter of a string * Taken from: https://stackoverflow.com/questions/1026069/how-do-i-make-the-first-letter-of-a-string-uppercase-in-javascript */ -export function capitalizeFirstLetter (string) { +export function capitalize (string) { return string.charAt(0).toUpperCase() + string.slice(1) } @@ -53,34 +64,6 @@ export function trimAndEllipse (string, stringNum) { return string } -/** -* Return a Date object given a datetime string of the format: "2016-09-10T07:00:00" -* @param {string} datetime -*/ -export function parseDate (datetime) { - return new Date(datetime.slice(0, 4), - datetime.slice(5, 7) - 1, - datetime.slice(8, 10), - datetime.slice(11, 13), - datetime.slice(14, 16), - datetime.slice(17, 19) - ) -} - -export function formatterWithYear (datetime) { - return timeFormat('%d %b %Y, %H:%M')(datetime) -} - -export function formatter (datetime) { - return timeFormat('%d %b, %H:%M')(datetime) -} - -export const parseTimestamp = ts => timeParse('%Y-%m-%dT%H:%M:%S')(ts) - -export function compareTimestamp (a, b) { - return (parseTimestamp(a.timestamp) > parseTimestamp(b.timestamp)) -} - /** * Inset the full source represenation from 'allSources' into an event. The * function is 'curried' to allow easy use with maps. To use for a single @@ -184,9 +167,17 @@ export function calcOpacity (num) { return base + (Math.min(0.5, 0.08 * (num - 1))) } -export const dateMin = function () { return Array.prototype.slice.call(arguments).reduce(function (a, b) { return a < b ? a : b }) } +export const dateMin = function () { + return Array.prototype.slice.call(arguments).reduce(function (a, b) { + return a < b ? a : b + }) +} -export const dateMax = function () { return Array.prototype.slice.call(arguments).reduce(function (a, b) { return a > b ? a : b }) } +export const dateMax = function () { + return Array.prototype.slice.call(arguments).reduce(function (a, b) { + return a > b ? a : b + }) +} /** Taken from * https://stackoverflow.com/questions/22697936/binary-search-in-javascript diff --git a/src/components/Card.jsx b/src/components/Card.jsx index aa07d24..735540c 100644 --- a/src/components/Card.jsx +++ b/src/components/Card.jsx @@ -1,11 +1,7 @@ import copy from '../common/data/copy.json' -import { - parseDate, - formatterWithYear -} from '../common/utilities' import React from 'react' -import CardTimestamp from './presentational/Card/Timestamp' +import CardTime from './presentational/Card/Time' import CardLocation from './presentational/Card/Location' import CardCaret from './presentational/Card/Caret' import CardTags from './presentational/Card/Tags' @@ -27,11 +23,9 @@ class Card extends React.Component { }) } - makeTimelabel (timestamp) { - if (timestamp === null) return null - const parsedTimestamp = parseDate(timestamp) - const timelabel = formatterWithYear(parsedTimestamp) - return timelabel + makeTimelabel (datetime) { + if (datetime === null) return null + return datetime.toLocaleDateString() } renderSummary () { @@ -87,8 +81,8 @@ class Card extends React.Component { } // NB: should be internaionalized. - renderTimestamp () { - let timelabel = this.makeTimelabel(this.props.event.timestamp) + renderTime() { + let timelabel = this.makeTimelabel(this.props.event.datetime) let precision = this.props.event.time_display if (precision === '_date_only') { @@ -104,7 +98,7 @@ class Card extends React.Component { } return ( -
- {this.renderTimestamp()} + {this.renderTime()} {this.renderLocation()}
{this.renderSummary()} diff --git a/src/components/Layout.js b/src/components/Layout.js index 4e83c05..f7ff3f5 100644 --- a/src/components/Layout.js +++ b/src/components/Layout.js @@ -16,7 +16,7 @@ import Notification from './Notification.jsx' import StaticPage from './StaticPage' import TemplateCover from './TemplateCover' -import { parseDate, binarySearch } from '../common/utilities' +import { binarySearch } from '../common/utilities' import { isMobile } from 'react-device-detect' class Dashboard extends React.Component { @@ -61,17 +61,18 @@ class Dashboard extends React.Component { const idx = binarySearch( events, selected, - (e1, e2) => new Date(e1.timestamp) - new Date(e2.timestamp) + (e1, e2) => e1.datetime - e2.datetime ) // check events before let ptr = idx - 1 - while (events[idx].timestamp === events[ptr].timestamp) { + console.log(events) + while (events[idx].datetime === events[ptr].datetime) { matchedEvents.push(events[ptr]) ptr -= 1 } // check events after ptr = idx + 1 - while (events[idx].timestamp === events[ptr].timestamp) { + while (events[idx].datetime === events[ptr].datetime) { matchedEvents.push(events[ptr]) ptr += 1 } diff --git a/src/components/Timeline.jsx b/src/components/Timeline.jsx index 3b272ad..c7c7dcd 100644 --- a/src/components/Timeline.jsx +++ b/src/components/Timeline.jsx @@ -5,7 +5,6 @@ import * as selectors from '../selectors' import hash from 'object-hash' import copy from '../common/data/copy.json' -import { formatterWithYear, parseDate } from '../common/utilities' import Header from './presentational/Timeline/Header' import Axis from './TimelineAxis.jsx' import Clip from './presentational/Timeline/Clip' @@ -28,14 +27,13 @@ class Timeline extends React.Component { dims: props.dimensions, scaleX: null, scaleY: null, - timerange: [null, null], + timerange: [null, null], // two datetimes dragPos0: null, transitionDuration: 300 } } componentDidMount () { - this.computeDims() this.addEventListeners() } @@ -60,7 +58,7 @@ class Timeline extends React.Component { if (hash(nextProps.app.selected) !== hash(this.props.app.selected)) { if (!!nextProps.app.selected && nextProps.app.selected.length > 0) { - this.onCenterTime(parseDate(nextProps.app.selected[0].timestamp)) + this.onCenterTime(nextProps.app.selected[0].datetime) } } } @@ -68,9 +66,10 @@ class Timeline extends React.Component { addEventListeners () { window.addEventListener('resize', () => { this.computeDims() }) let element = document.querySelector('.timeline-wrapper') - element.addEventListener('transitionend', (event) => { - this.computeDims() - }) + if (element !== null) + element.addEventListener('transitionend', (event) => { + this.computeDims() + }) } makeScaleX () { @@ -191,8 +190,8 @@ class Timeline extends React.Component { if (rangeLimits) { // If the store contains absolute time limits, // make sure the zoom doesn't go over them - const minDate = parseDate(rangeLimits[0]) - const maxDate = parseDate(rangeLimits[1]) + const minDate = rangeLimits[0] + const maxDate = rangeLimits[1] if (newDomain0 < minDate) { newDomain0 = minDate @@ -243,8 +242,8 @@ class Timeline extends React.Component { if (rangeLimits) { // If the store contains absolute time limits, // make sure the zoom doesn't go over them - const minDate = parseDate(rangeLimits[0]) - const maxDate = parseDate(rangeLimits[1]) + const minDate = rangeLimits[0] + const maxDate = rangeLimits[1] newDomain0 = (newDomain0 < minDate) ? minDate : newDomain0 newDomainF = (newDomainF > maxDate) ? maxDate : newDomainF @@ -262,8 +261,8 @@ class Timeline extends React.Component { this.props.methods.onUpdateTimerange(this.state.timerange) } - getDatetimeX (timestamp) { - return this.state.scaleX(parseDate(timestamp)) + getDatetimeX (datetime) { + return this.state.scaleX(datetime) } /** @@ -294,8 +293,8 @@ class Timeline extends React.Component {
{ this.onClickArrow() }} hideInfo={isNarrative} /> diff --git a/src/components/presentational/Card/Category.js b/src/components/presentational/Card/Category.js index 2cc9c22..2000293 100644 --- a/src/components/presentational/Card/Category.js +++ b/src/components/presentational/Card/Category.js @@ -1,12 +1,12 @@ import React from 'react' -import { capitalizeFirstLetter } from '../../../common/utilities.js' +import { capitalize } from '../../../common/utilities.js' const CardCategory = ({ categoryTitle, categoryLabel, color }) => (

{categoryTitle}

- {capitalizeFirstLetter(categoryLabel)} + {capitalize(categoryLabel)}

diff --git a/src/components/presentational/Card/Timestamp.js b/src/components/presentational/Card/Time.js similarity index 89% rename from src/components/presentational/Card/Timestamp.js rename to src/components/presentational/Card/Time.js index c95ed04..3fe26e9 100644 --- a/src/components/presentational/Card/Timestamp.js +++ b/src/components/presentational/Card/Time.js @@ -3,7 +3,7 @@ import React from 'react' import copy from '../../../common/data/copy.json' import { isNotNullNorUndefined } from '../../../common/utilities' -const CardTimestamp = ({ timelabel, language, precision }) => { +const CardTime = ({ timelabel, language, precision }) => { // const daytimeLang = copy[language].cardstack.timestamp // const estimatedLang = copy[language].cardstack.estimated const unknownLang = copy[language].cardstack.unknown_time @@ -29,4 +29,4 @@ const CardTimestamp = ({ timelabel, language, precision }) => { } } -export default CardTimestamp +export default CardTime diff --git a/src/components/presentational/Timeline/Events.js b/src/components/presentational/Timeline/Events.js index df568dd..81f6ae9 100644 --- a/src/components/presentational/Timeline/Events.js +++ b/src/components/presentational/Timeline/Events.js @@ -92,19 +92,26 @@ const TimelineEvents = ({ } } - let defaultY = getCategoryY(event.category) + let eventY = getCategoryY(event.category) + const isNonlocated = !event.latitude && !event.longitude + if (features.GRAPH_NONLOCATED && isNonlocated) { + const { project } = event + if (project) { + const { offset } = projects[project] + eventY = dims.marginTop + offset + sizes.eventDotR + } + } + let colour = event.colour ? event.colour : getCategoryColor(event.category) const styles = { fill: colour, - fillOpacity: defaultY > 0 ? calcOpacity(1) : 0, + fillOpacity: eventY > 0 ? calcOpacity(1) : 0, transition: `transform ${transitionDuration / 1000}s ease` } return renderShape(event, styles, { - x: getDatetimeX(event.timestamp), - y: (features.GRAPH_NONLOCATED && !event.latitude && !event.longitude) - ? event.projectOffset >= 0 ? dims.trackHeight - event.projectOffset : dims.marginTop - : getCategoryY ? defaultY : () => null, + x: getDatetimeX(event.datetime), + y: eventY, onSelect: () => onSelect(event), dims, highlights: features.HIGHLIGHT_GROUPS ? getHighlights(event.tags[features.HIGHLIGHT_GROUPS.tagIndexIndicatingGroup]) : [], @@ -113,11 +120,12 @@ const TimelineEvents = ({ } /* set `renderProjects` */ + // TODO(lachlan): remove hardcoded 'Legislation' let renderProjects = () => null if (features.GRAPH_NONLOCATED) { renderProjects = function () { return - {projects.map(project => console.log(project)} getX={getDatetimeX} diff --git a/src/components/presentational/Timeline/Header.js b/src/components/presentational/Timeline/Header.js index a942cb7..b9f0f25 100644 --- a/src/components/presentational/Timeline/Header.js +++ b/src/components/presentational/Timeline/Header.js @@ -1,15 +1,19 @@ import React from 'react' -const TimelineHeader = ({ title, date0, date1, onClick, hideInfo }) => ( -
-
onClick()}> -

+const TimelineHeader = ({ title, from, to, onClick, hideInfo }) => { + const d0 = from && from.toLocaleDateString() + const d1 = to && to.toLocaleDateString() + return ( +
+
onClick()}> +

+
+
+

{title}

+

{d0} - {d1}

+
-
-

{title}

-

{date0} - {date1}

-
-
-) + ) +} export default TimelineHeader diff --git a/src/components/presentational/Timeline/Labels.js b/src/components/presentational/Timeline/Labels.js index 76e07dc..5521677 100644 --- a/src/components/presentational/Timeline/Labels.js +++ b/src/components/presentational/Timeline/Labels.js @@ -1,7 +1,5 @@ import React from 'react' -import { formatterWithYear } from '../../../js/utilities.js' - const TimelineLabels = ({ dims, timelabels }) => { return ( @@ -24,7 +22,7 @@ const TimelineLabels = ({ dims, timelabels }) => { x='5' y='15' > - {formatterWithYear(timelabels[0])} + {timelabels[0]} { y='15' style={{ textAnchor: 'end' }} > - {formatterWithYear(timelabels[1])} + {timelabels[1]} ) diff --git a/src/components/presentational/Timeline/Project.js b/src/components/presentational/Timeline/Project.js index dfd7027..a0ce7db 100644 --- a/src/components/presentational/Timeline/Project.js +++ b/src/components/presentational/Timeline/Project.js @@ -2,21 +2,23 @@ import React from 'react' import { sizes } from '../../../common/global' export default ({ - id, offset, + id, start, end, getX, + y, dims, colour, onClick }) => { const length = getX(end) - getX(start) + if (offset === undefined) return null return { - const stepTime = parseDate(step.timestamp) + const stepTime = step.datetime if (stepTime < minTime) minTime = stepTime if (stepTime > maxTime) maxTime = stepTime diff --git a/src/reducers/domain.js b/src/reducers/domain.js index dc798db..c0c3c27 100644 --- a/src/reducers/domain.js +++ b/src/reducers/domain.js @@ -1,13 +1,9 @@ import initial from '../store/initial.js' import { UPDATE_DOMAIN, MARK_NOTIFICATIONS_READ } from '../actions' -import { parseDateTimes } from './utils/helpers.js' -import { validateDomain } from './utils/validators.js' +import { validateDomain } from './validate/validators.js' function updateDomain (domainState, action) { - action.domain.events = parseDateTimes(action.domain.events) - - // return Object.assign({}, domainState, validate(action.domain)) return { ...domainState, ...validateDomain(action.domain) diff --git a/src/reducers/utils/helpers.js b/src/reducers/utils/helpers.js deleted file mode 100644 index cd52380..0000000 --- a/src/reducers/utils/helpers.js +++ /dev/null @@ -1,20 +0,0 @@ -import { timeFormat, timeParse } from 'd3' - -export function parseDateTimes (arrayToParse) { - const parsedArray = [] - - arrayToParse.forEach(item => { - let incomingDateTime = `${item.date}T00:00` - if (item.time) incomingDateTime = `${item.date}T${item.time}` - const parser = timeParse(process.env.INCOMING_DATETIME_FORMAT) - item.timestamp = timeFormat('%Y-%m-%dT%H:%M:%S')(parser(incomingDateTime)) - - parsedArray.push(item) - }) - - return parsedArray -} - -export function capitalize (string) { - return string.charAt(0).toUpperCase() + string.slice(1) -} diff --git a/src/reducers/schema/categorySchema.js b/src/reducers/validate/categorySchema.js similarity index 100% rename from src/reducers/schema/categorySchema.js rename to src/reducers/validate/categorySchema.js diff --git a/src/reducers/schema/eventSchema.js b/src/reducers/validate/eventSchema.js similarity index 90% rename from src/reducers/schema/eventSchema.js rename to src/reducers/validate/eventSchema.js index 376315e..b96f8cd 100644 --- a/src/reducers/schema/eventSchema.js +++ b/src/reducers/validate/eventSchema.js @@ -16,7 +16,6 @@ const eventSchema = Joi.object().keys({ sources: Joi.array(), tags: Joi.array().allow(''), comments: Joi.string().allow(''), - timestamp: Joi.string(), time_display: Joi.string().allow(''), // nested @@ -25,7 +24,6 @@ const eventSchema = Joi.object().keys({ colour: Joi.string().allow('') }) .and('latitude', 'longitude') - .and('date', 'timestamp') - .or('timestamp', 'latitude') + .or('date', 'latitude') export default eventSchema diff --git a/src/reducers/schema/narrativeSchema.js b/src/reducers/validate/narrativeSchema.js similarity index 100% rename from src/reducers/schema/narrativeSchema.js rename to src/reducers/validate/narrativeSchema.js diff --git a/src/reducers/schema/shapeSchema.js b/src/reducers/validate/shapeSchema.js similarity index 100% rename from src/reducers/schema/shapeSchema.js rename to src/reducers/validate/shapeSchema.js diff --git a/src/reducers/schema/siteSchema.js b/src/reducers/validate/siteSchema.js similarity index 100% rename from src/reducers/schema/siteSchema.js rename to src/reducers/validate/siteSchema.js diff --git a/src/reducers/schema/sourceSchema.js b/src/reducers/validate/sourceSchema.js similarity index 100% rename from src/reducers/schema/sourceSchema.js rename to src/reducers/validate/sourceSchema.js diff --git a/src/reducers/utils/validators.js b/src/reducers/validate/validators.js similarity index 88% rename from src/reducers/utils/validators.js rename to src/reducers/validate/validators.js index ade0ec6..a70860f 100644 --- a/src/reducers/utils/validators.js +++ b/src/reducers/validate/validators.js @@ -1,13 +1,13 @@ import Joi from 'joi' -import eventSchema from '../schema/eventSchema' -import categorySchema from '../schema/categorySchema' -import siteSchema from '../schema/siteSchema' -import narrativeSchema from '../schema/narrativeSchema' -import sourceSchema from '../schema/sourceSchema' -import shapeSchema from '../schema/shapeSchema' +import eventSchema from './eventSchema' +import categorySchema from './categorySchema' +import siteSchema from './siteSchema' +import narrativeSchema from './narrativeSchema' +import sourceSchema from './sourceSchema' +import shapeSchema from './shapeSchema' -import { capitalize } from './helpers.js' +import { calcDatetime, capitalize } from '../../common/utilities' /* * Create an error notification object @@ -153,8 +153,12 @@ export function validateDomain (domain) { } sanitizedDomain.tags = domain.tags - // sort events by timestamp - sanitizedDomain.events.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp)) + // append events with datetime and sort + sanitizedDomain.events.forEach(event => { + event.datetime = calcDatetime(event.date, event.time) + }) + + sanitizedDomain.events.sort((a, b) => a.datetime - b.datetime) return sanitizedDomain } diff --git a/src/selectors/helpers.js b/src/selectors/helpers.js index d7e7257..fb89c17 100644 --- a/src/selectors/helpers.js +++ b/src/selectors/helpers.js @@ -1,4 +1,3 @@ -import { parseTimestamp } from '../common/utilities' /** * Some handy helpers */ @@ -8,7 +7,7 @@ import { parseTimestamp } from '../common/utilities' * returns true/false if the event falls within timeRange */ export function isTimeRangedIn (event, timeRange) { - const eventTime = parseTimestamp(event.timestamp) + const eventTime = event.datetime return ( timeRange[0] < eventTime && eventTime < timeRange[1] diff --git a/src/selectors/index.js b/src/selectors/index.js index d549c00..2e651c7 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -1,5 +1,5 @@ import { createSelector } from 'reselect' -import { compareTimestamp, insetSourceFrom, dateMin, dateMax } from '../common/utilities' +import { insetSourceFrom, dateMin, dateMax } from '../common/utilities' import { isTimeRangedIn } from './helpers' import { sizes } from '../common/global' @@ -96,7 +96,7 @@ export const selectNarratives = createSelector( Object.keys(narratives).forEach(key => { const steps = narratives[key].steps - steps.sort(compareTimestamp) + steps.sort((a, b) => a.datetime - b.datetime) if (narrativesMeta.find(n => n.id === key)) { narratives[key] = { @@ -159,29 +159,64 @@ export const selectEventsWithProjects = createSelector( if (!features.GRAPH_NONLOCATED) { return [events, []] } + const projSize = 2 * sizes.eventDotR const projectIdx = features.GRAPH_NONLOCATED.projectIdx || 0 const getProject = ev => ev.tags[projectIdx] const projects = {} + // get all projects events = events.reduce((acc, event) => { const project = event.tags.length >= 1 && !event.latitude && !event.longitude ? getProject(event) : null // add project if it doesn't exist if (project !== null) { if (projects.hasOwnProperty(project)) { - projects[project].start = dateMin(projects[project].start, event.timestamp) - projects[project].end = dateMax(projects[project].end, event.timestamp) + projects[project].start = dateMin(projects[project].start, event.datetime) + projects[project].end = dateMax(projects[project].end, event.datetime) } else { - projects[project] = { start: event.timestamp, end: event.timestamp } + projects[project] = { start: event.datetime, end: event.datetime, key: project } } } acc.push({ ...event, project }) return acc }, []) - const projKeys = Object.keys(projects) + let projObjs = Object.values(projects) + projObjs.sort((a, b) => a.start - b.start) + + // active projects is a data structure with projObjs.length empty slots + let activeProjs = {} + projObjs.forEach((_, idx) => { activeProjs[idx] = null }) + + const projectsWithOffset = projObjs.reduce((acc, proj, theIdx) => { + if (theIdx >= 1) { acc[proj.key] = proj; return acc } + // remove any project that have ended from slots + let j = 0 + while (j < projObjs.length) { + if (!activeProjs[j]) { + j++ + continue + } + const projInSlot = projects[activeProjs[j]] + if (projInSlot.end > proj.start) { + activeProjs[j] = null + } + j++ + } + let i = 0 + // find the first empty slot + while (activeProjs[i]) i++ + // put proj in slot + activeProjs[i] = proj.key + + proj.offset = i * projSize + console.log(`${proj.key}:-- ${proj.offset}`) + acc[proj.key] = proj + return acc + }, {}) + + /* events = events.reduce((acc, event) => { - // infer activeProjects from timestamp const activeProjects = [] projKeys.forEach((k, idx) => { if (event.timestamp >= projects[k].start && event.timestamp <= projects[k].end) { @@ -192,11 +227,16 @@ export const selectEventsWithProjects = createSelector( // infer projectOffset using activeProjects // TODO(lachlan) projects get overlaid if they start at the same time... const activeIdx = activeProjects.indexOf(event.project) - let projectOffset = (activeIdx + 3) * (2.5 * sizes.eventDotR) + let projectOffset = activeIdx * projSize if (activeIdx === -1) { + // project isn't in previously calculated list of projects projectOffset = -1 } - if (event.project !== null && !projects[event.project].hasOwnProperty('offset')) { + if (event.project !== null) { + if (projects[event.project].hasOwnProperty('offset')) { + // project is already active + projectOffset = (activeIdx + 1) * projSize + } projects[event.project].offset = projectOffset projects[event.project].category = event.category } else if (event.project !== null) { @@ -205,8 +245,9 @@ export const selectEventsWithProjects = createSelector( acc.push({ ...event, projectOffset }) return acc }, []) + */ - return [events, projects] + return [events, projectsWithOffset] } ) @@ -223,15 +264,7 @@ export const selectProjects = createSelector( if (!features.GRAPH_NONLOCATED) { return [] } - // reduce projEvents to get _events - const projects = [] - const projKeys = Object.keys(eventsWithProjects[1]) - - projKeys.forEach(projId => { - projects.push({ ...eventsWithProjects[1][projId], id: projId }) - }) - - return projects + return eventsWithProjects[1] } ) diff --git a/src/store/initial.js b/src/store/initial.js index 978940a..b60c847 100644 --- a/src/store/initial.js +++ b/src/store/initial.js @@ -60,12 +60,12 @@ const initial = { }, timeline: { dimensions: { - height: 250, + height: 450, width: 0, marginLeft: 100, marginTop: 15, marginBottom: 60, - contentHeight: 200, + contentHeight: 400, width_controls: 100 }, range: [ diff --git a/yarn.lock b/yarn.lock index 8f6a7a6..09eaecf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5855,6 +5855,11 @@ mocha@^5.2.0: mkdirp "0.5.1" supports-color "5.4.0" +moment@^2.26.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a" + integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -7200,6 +7205,11 @@ react-tabs@3.0.0: classnames "^2.2.0" prop-types "^15.5.0" +react-zoom-pan-pinch@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/react-zoom-pan-pinch/-/react-zoom-pan-pinch-1.6.1.tgz#da16267c258ab37e8ebcdc7c252794a9633e91ec" + integrity sha512-J2eM0gZ04XiUWvmKZrOhSAB2zjyoK7kw2POIeN1X0yTTlmp6HPGV0zYfjnlkhgt8nQwpvXAbsF/oAnkuiwk1kA== + react@^16.6.3: version "16.6.3" resolved "https://registry.yarnpkg.com/react/-/react-16.6.3.tgz#25d77c91911d6bbdd23db41e70fb094cc1e0871c"