From 8a47bb4b02db791dddcfa975a5ac9652547a0573 Mon Sep 17 00:00:00 2001 From: marcelines Date: Thu, 18 May 2023 13:54:45 +0100 Subject: [PATCH] Add burnup chart component (#401) * feat: add chart to website WIP * fix: minor improvements * feat: add animation to areas on load * feat: adds animation to rest of the chart elements * feat: refact chart component * feat: add loading state to chart component * feat: add empty state and fixed some issues * Set up website deployment (#391) * env * vercel.json * turbo * u * root * cwd * use cwd option (#393) * fix: remove border width from progress bar * fix: changes from review * fix: removes spacing with first tick in X Axis component * update assertion --------- Co-authored-by: Felicio Mununga Co-authored-by: Pavel Prichodko <14926950+prichodko@users.noreply.github.com> --- apps/web/styles/app.css | 12 - apps/website/package.json | 6 + apps/website/public/assets/chart/empty.png | Bin 0 -> 28580 bytes apps/website/src/components/chart/chart.tsx | 47 + .../src/components/chart/components/areas.tsx | 98 ++ .../chart/components/assets/index.tsx | 2 + .../chart/components/assets/line-a.tsx | 15 + .../chart/components/assets/line-b.tsx | 15 + .../chart/components/chart-component.tsx | 234 +++++ .../chart/components/chart-tooltip.tsx | 115 +++ .../src/components/chart/components/empty.tsx | 48 + .../src/components/chart/components/index.tsx | 3 + .../src/components/chart/components/lines.tsx | 73 ++ .../components/chart/components/loading.tsx | 39 + .../components/chart/components/markers.tsx | 74 ++ .../src/components/chart/helpers/get-data.ts | 15 + .../src/components/chart/hooks/index.ts | 2 + .../components/chart/hooks/use-animations.ts | 99 ++ .../chart/hooks/use-chart-tooltip.ts | 129 +++ .../src/components/chart/utils/format-time.ts | 13 + .../components/chart/utils/get-percentage.ts | 8 + apps/website/src/components/epic-overview.tsx | 855 +++--------------- apps/website/src/styles/app.css | 36 + packages/components/.storybook/preview.tsx | 1 - .../skeleton/skeleton.css} | 0 packages/components/src/skeleton/skeleton.tsx | 2 + yarn.lock | 759 +++++++++++++++- 27 files changed, 1936 insertions(+), 764 deletions(-) create mode 100644 apps/website/public/assets/chart/empty.png create mode 100644 apps/website/src/components/chart/chart.tsx create mode 100644 apps/website/src/components/chart/components/areas.tsx create mode 100644 apps/website/src/components/chart/components/assets/index.tsx create mode 100644 apps/website/src/components/chart/components/assets/line-a.tsx create mode 100644 apps/website/src/components/chart/components/assets/line-b.tsx create mode 100644 apps/website/src/components/chart/components/chart-component.tsx create mode 100644 apps/website/src/components/chart/components/chart-tooltip.tsx create mode 100644 apps/website/src/components/chart/components/empty.tsx create mode 100644 apps/website/src/components/chart/components/index.tsx create mode 100644 apps/website/src/components/chart/components/lines.tsx create mode 100644 apps/website/src/components/chart/components/loading.tsx create mode 100644 apps/website/src/components/chart/components/markers.tsx create mode 100644 apps/website/src/components/chart/helpers/get-data.ts create mode 100644 apps/website/src/components/chart/hooks/index.ts create mode 100644 apps/website/src/components/chart/hooks/use-animations.ts create mode 100644 apps/website/src/components/chart/hooks/use-chart-tooltip.ts create mode 100644 apps/website/src/components/chart/utils/format-time.ts create mode 100644 apps/website/src/components/chart/utils/get-percentage.ts create mode 100644 apps/website/src/styles/app.css rename packages/components/{.storybook/components.css => src/skeleton/skeleton.css} (100%) diff --git a/apps/web/styles/app.css b/apps/web/styles/app.css index 35c5d522..bf7af298 100644 --- a/apps/web/styles/app.css +++ b/apps/web/styles/app.css @@ -79,15 +79,3 @@ body, display: none; } } - -@keyframes gradient { - 0% { - background-position: 0% 50%; - } - 50% { - background-position: 100% 50%; - } - 100% { - background-position: 0% 50%; - } -} diff --git a/apps/website/package.json b/apps/website/package.json index 773ebbc4..c2010e8a 100644 --- a/apps/website/package.json +++ b/apps/website/package.json @@ -14,6 +14,7 @@ "dependencies": { "@radix-ui/react-dialog": "^1.0.3", "@radix-ui/react-navigation-menu": "^1.1.2", + "@react-spring/web": "^9.7.2", "@scure/base": "^1.1.1", "@status-im/colors": "*", "@status-im/components": "*", @@ -21,6 +22,9 @@ "@status-im/js": "*", "@tamagui/next-theme": "1.11.1", "class-variance-authority": "^0.6.0", + "@visx/visx": "^2.18.0", + "d3-array": "^3.2.3", + "d3-time-format": "^4.1.0", "next": "13.2.4", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -30,6 +34,8 @@ "devDependencies": { "@achingbrain/ssdp": "^4.0.1", "@tamagui/next-plugin": "1.11.1", + "@types/d3-array": "^3.0.4", + "@types/d3-time-format": "^4.0.0", "@types/node": "^18.11.11", "@types/react": "^18.0.33", "@types/react-dom": "^18.0.11", diff --git a/apps/website/public/assets/chart/empty.png b/apps/website/public/assets/chart/empty.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a0b413b38960b4d6fe9834a9a04cb02663cbe8 GIT binary patch literal 28580 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 cw7K;E1G;7-%ka3n{Qv*}07*qoM6N<$f { + const { data, isLoading, ...rest } = props + + if (isLoading) { + return ( + + + + ) + } + + if (!data.length) { + return ( + + + + ) + } + + return ( + + {({ width }) => { + return + }} + + ) +} + +export { Chart } +export type { Props as ChartProps, DayType } diff --git a/apps/website/src/components/chart/components/areas.tsx b/apps/website/src/components/chart/components/areas.tsx new file mode 100644 index 00000000..13aa88ea --- /dev/null +++ b/apps/website/src/components/chart/components/areas.tsx @@ -0,0 +1,98 @@ +import { animated } from '@react-spring/web' +import { curveMonotoneX } from '@visx/curve' +import { LinearGradient } from '@visx/gradient' +import { AreaClosed } from '@visx/shape' + +import { colors } from './chart-component' + +import type { SpringValue } from '@react-spring/web' +import type { ScaleLinear, ScaleTime } from 'd3-scale' + +type Datum = { + date: Date + value: number +} + +type Props = { + yScale: ScaleLinear + xScale: ScaleTime + totalIssuesData: Datum[] + closedIssuesData: Datum[] + clipPathAnimation: { + clipPath: SpringValue + } +} + +const AnimatedAreaClosed = animated(AreaClosed) + +const Areas = (props: Props) => { + const { + clipPathAnimation, + closedIssuesData, + totalIssuesData, + xScale, + yScale, + } = props + return ( + <> + + + + + + {/* Total issues area */} + { + const datum = d as Datum + return xScale(datum.date) + }} + y={d => { + const datum = d as Datum + return yScale(datum.value) + }} + yScale={yScale} + fill="url(#gradient)" + curve={curveMonotoneX} + style={{ ...clipPathAnimation, zIndex: 10 }} + /> + + {/* Closed issues area */} + { + const datum = d as Datum + return xScale(datum.date) + }} + y={d => { + const datum = d as Datum + return yScale(datum.value) + }} + yScale={yScale} + fill="url(#gradient-open)" + curve={curveMonotoneX} + style={{ ...clipPathAnimation, zIndex: 10 }} + /> + + ) +} + +export { Areas } diff --git a/apps/website/src/components/chart/components/assets/index.tsx b/apps/website/src/components/chart/components/assets/index.tsx new file mode 100644 index 00000000..ba63637f --- /dev/null +++ b/apps/website/src/components/chart/components/assets/index.tsx @@ -0,0 +1,2 @@ +export { LineA } from './line-a' +export { LineB } from './line-b' diff --git a/apps/website/src/components/chart/components/assets/line-a.tsx b/apps/website/src/components/chart/components/assets/line-a.tsx new file mode 100644 index 00000000..926e4cc1 --- /dev/null +++ b/apps/website/src/components/chart/components/assets/line-a.tsx @@ -0,0 +1,15 @@ +const LineA = () => { + return ( + + + + ) +} + +export { LineA } diff --git a/apps/website/src/components/chart/components/assets/line-b.tsx b/apps/website/src/components/chart/components/assets/line-b.tsx new file mode 100644 index 00000000..7318de3b --- /dev/null +++ b/apps/website/src/components/chart/components/assets/line-b.tsx @@ -0,0 +1,15 @@ +const LineB = () => { + return ( + + + + ) +} + +export { LineB } diff --git a/apps/website/src/components/chart/components/chart-component.tsx b/apps/website/src/components/chart/components/chart-component.tsx new file mode 100644 index 00000000..49cc2fbb --- /dev/null +++ b/apps/website/src/components/chart/components/chart-component.tsx @@ -0,0 +1,234 @@ +import { useMemo } from 'react' + +import { animated } from '@react-spring/web' +import { Axis } from '@visx/axis' +import { GridColumns } from '@visx/grid' +import { Group } from '@visx/group' +import { scaleLinear, scaleTime } from '@visx/scale' +import { extent, max } from 'd3-array' + +import { getClosedIssues, getTotalIssues } from '../helpers/get-data' +import { useAnimations, useChartTooltip } from '../hooks/' +import { format } from '../utils/format-time' +import { Areas } from './areas' +import { ChartTooltip } from './chart-tooltip' +import { Lines } from './lines' +import { Markers } from './markers' + +import type { DayType } from '../chart' + +// defining colors +export const colors = { + total: '#E95460', + closed: '#23ADA0', + background: '#F0F2F5', + marker: '#09101C', + totalGradient: 'rgba(233, 84, 96, 0.3)', + closedGradient: 'rgba(35, 173, 160, 0.3)', + white: '#FFF', +} as const + +interface Props { + data: DayType[] + height?: number + width?: number +} + +const AnimatedGridColumns = animated(GridColumns) + +const ChartComponent = (props: Props): JSX.Element => { + const { data, width: defaultWidth, height: defaultHeight } = props + + // Extract dates, open issues, and closed issues from data + const dates = data.map(d => new Date(d.date)) + + // Define dimensions + const height = defaultHeight || 300 + const width = defaultWidth || 300 + const margin = { top: 20, right: 0, bottom: 30, left: 26 } + const innerWidth = (width || 0) - margin.left - margin.right + const innerHeight = height - margin.top - margin.bottom + + const filteredDates = dates.filter(Boolean) // filters out undefined values + // Calculate total issues by summing open and closed issues + const totalIssues = data.map(d => d.open_issues + d.closed_issues) + + const xDomain = extent(filteredDates) as [Date, Date] + const xScale = scaleTime({ + domain: xDomain, + range: [0, innerWidth], + }) + + const numTicksBottom = Math.min(data.length, 12) + + const yScale = scaleLinear({ + domain: [0, max(totalIssues) || 0], + range: [innerHeight, 0], + nice: true, + }) + + const { tooltipData, updateTooltip, hideTooltip, tooltipOpen } = + useChartTooltip({ + data, + margin, + dates, + innerWidth, + }) + + const { + circleSpringClosed, + circleSpringTotal, + clipPathAnimation, + drawingGridColumns, + drawingLineStyle, + opacityAnimation, + tooltipAnimation, + } = useAnimations({ + data, + margin, + innerHeight, + tooltipData, + yScale, + xScale, + }) + + // Convert data to array of objects with `date` and `value` properties + const totalIssuesData = useMemo( + () => + data.map(d => ({ + date: new Date(d.date), + value: getTotalIssues(d), + })), + [data] + ) + + const closedIssuesData = useMemo( + () => + data.map(d => ({ + date: new Date(d.date), + value: getClosedIssues(d), + })), + [data] + ) + + return ( +
    + + + {/* x-axis */} + { + const textAnchor = + index === 0 + ? 'start' + : index === data.length - 1 + ? 'end' + : 'middle' + return { + dy: '.33em', + fill: '#A1ABBD', + fontFamily: 'Inter, sans-serif', + fontSize: 11, + textAnchor, + } + }} + tickFormat={value => { + if (typeof value === 'number') { + return value.toString() // Handle number values + } else if (value instanceof Date) { + // Specify the desired date format + return format(value) // Handle date values + } else { + return '' + } + }} + /> + {/* y-axis */} + ( + + {formattedValue} + + )} + /> + + + + + + + + {tooltipOpen && ( + + )} + hideTooltip()} + /> + + + {/* render a tooltip */} + {tooltipOpen && ( + + )} +
    + ) +} + +export { ChartComponent } diff --git a/apps/website/src/components/chart/components/chart-tooltip.tsx b/apps/website/src/components/chart/components/chart-tooltip.tsx new file mode 100644 index 00000000..1b17e042 --- /dev/null +++ b/apps/website/src/components/chart/components/chart-tooltip.tsx @@ -0,0 +1,115 @@ +import { animated } from '@react-spring/web' +import { Text } from '@status-im/components' +import { DoneIcon, OpenIcon } from '@status-im/icons' +import { Stack } from '@tamagui/core' +import { defaultStyles, TooltipWithBounds } from '@visx/tooltip' + +import type { TooltipData } from '../hooks/use-chart-tooltip' +import type { SpringValue } from '@react-spring/web' + +const AnimatedTooltip = animated(TooltipWithBounds) + +type Props = { + tooltipData: TooltipData + opacityAnimation: { + opacity: SpringValue + } + tooltipAnimation: { + x: SpringValue + y: SpringValue + } +} + +// defining tooltip styles +const tooltipStyles: React.CSSProperties = { + ...defaultStyles, + minWidth: 272, + padding: 12, + backgroundColor: '#FFF', + border: '1px solid #F0F2F5', + boxShadow: '0px 2px 20px rgba(9, 16, 28, 0.04)', + borderRadius: 20, + marginLeft: 25, +} + +const ChartTooltip = (props: Props) => { + const { tooltipData, opacityAnimation, tooltipAnimation } = props + return ( + + + + {tooltipData.totalIssues} + + + + issues + + + + + + {tooltipData.formattedDate} + + + + + + + + + + + {tooltipData.openIssues} open + + + + + {`${tooltipData.openIssuesPercentage}%`} + + + + + + + + {tooltipData.closedIssues} closes + + + + + {`${tooltipData.completedIssuesPercentage}%`} + + + + + ) +} + +export { ChartTooltip } diff --git a/apps/website/src/components/chart/components/empty.tsx b/apps/website/src/components/chart/components/empty.tsx new file mode 100644 index 00000000..c2a965f4 --- /dev/null +++ b/apps/website/src/components/chart/components/empty.tsx @@ -0,0 +1,48 @@ +import { Image, Text } from '@status-im/components' + +import { LineA, LineB } from './assets' + +const Empty = () => { + return ( +
    +
    +
    + +
    + + No results found + +
    + + Try adjusting your search or filter to find what you’re looking for. + +
    +
    + +
    +
    + +
    +
    +
    + {Array.from({ length: 12 }).map((_, i) => ( +
    + ))} +
    +
    +
    + ) +} + +export { Empty } diff --git a/apps/website/src/components/chart/components/index.tsx b/apps/website/src/components/chart/components/index.tsx new file mode 100644 index 00000000..5ebd09e1 --- /dev/null +++ b/apps/website/src/components/chart/components/index.tsx @@ -0,0 +1,3 @@ +export { ChartComponent } from './chart-component' +export { Empty } from './empty' +export { Loading } from './loading' diff --git a/apps/website/src/components/chart/components/lines.tsx b/apps/website/src/components/chart/components/lines.tsx new file mode 100644 index 00000000..0ef17d04 --- /dev/null +++ b/apps/website/src/components/chart/components/lines.tsx @@ -0,0 +1,73 @@ +import { animated } from '@react-spring/web' +import { curveMonotoneX } from '@visx/curve' +import { LinePath } from '@visx/shape' + +import { colors } from './chart-component' + +import type { SpringValue } from '@react-spring/web' +import type { ScaleLinear, ScaleTime } from 'd3-scale' + +type Datum = { + date: Date + value: number +} + +type Props = { + yScale: ScaleLinear + xScale: ScaleTime + totalIssuesData: Datum[] + closedIssuesData: Datum[] + drawingLineStyle: { + strokeDasharray: SpringValue + } +} + +const AnimatedLinePath = animated(LinePath) + +const Lines = (props: Props) => { + const { + closedIssuesData, + drawingLineStyle, + xScale, + yScale, + totalIssuesData, + } = props + return ( + <> + {/* Total issues line */} + { + const datum = d as Datum + return xScale(datum.date) + }} + y={d => { + const datum = d as Datum + return yScale(datum.value) + }} + stroke={colors.total} + strokeWidth={2} + curve={curveMonotoneX} + style={drawingLineStyle} + /> + + {/* Closed issues line */} + { + const datum = d as Datum + return xScale(datum.date) + }} + y={d => { + const datum = d as Datum + return yScale(datum.value) + }} + stroke={colors.closed} + strokeWidth={2} + curve={curveMonotoneX} + style={drawingLineStyle} + /> + + ) +} +export { Lines } diff --git a/apps/website/src/components/chart/components/loading.tsx b/apps/website/src/components/chart/components/loading.tsx new file mode 100644 index 00000000..1c9f1492 --- /dev/null +++ b/apps/website/src/components/chart/components/loading.tsx @@ -0,0 +1,39 @@ +import { Skeleton } from '@status-im/components' + +const Loading = () => { + return ( +
    +
    +
    +
    + {Array.from({ length: 5 }).map((_, i) => ( + + ))} +
    +
    + {Array.from({ length: 12 }).map((_, i) => ( +
    + ))} +
    +
    +
    + {Array.from({ length: 12 }).map((_, i) => ( + + ))} +
    +
    + ) +} + +export { Loading } diff --git a/apps/website/src/components/chart/components/markers.tsx b/apps/website/src/components/chart/components/markers.tsx new file mode 100644 index 00000000..66a2b3a2 --- /dev/null +++ b/apps/website/src/components/chart/components/markers.tsx @@ -0,0 +1,74 @@ +import { animated } from '@react-spring/web' +import { GlyphCircle } from '@visx/glyph' +import { Group } from '@visx/group' +import { Line } from '@visx/shape' + +import { colors } from './chart-component' + +import type { SpringValue } from '@react-spring/web' + +type Props = { + innerHeight: number + circleSpringTotal: { + x: SpringValue + y: SpringValue + } + opacityAnimation: { + opacity: SpringValue + } + circleSpringClosed: { + x: SpringValue + y: SpringValue + } +} + +const AnimatedCircle = animated(GlyphCircle) +const AnimatedLine = animated(Line) +const AnimatedGroup = animated(Group) + +const Markers = (props: Props) => { + const { + innerHeight, + circleSpringTotal, + opacityAnimation, + circleSpringClosed, + } = props + + return ( + <> + + + + + + + ) +} + +export { Markers } diff --git a/apps/website/src/components/chart/helpers/get-data.ts b/apps/website/src/components/chart/helpers/get-data.ts new file mode 100644 index 00000000..6e056f2c --- /dev/null +++ b/apps/website/src/components/chart/helpers/get-data.ts @@ -0,0 +1,15 @@ +import type { DayType } from '../chart' + +/** + * Gets the total issues of a day + * @param d - the day to get the total issues + * @returns the total issues of a day + **/ +export const getTotalIssues = (d: DayType) => d?.open_issues + d?.closed_issues + +/** + * Gets the closed issues of a day + * @param d - the day to get the closes issues + * @returns the total issues of a day + **/ +export const getClosedIssues = (d: DayType) => d?.closed_issues diff --git a/apps/website/src/components/chart/hooks/index.ts b/apps/website/src/components/chart/hooks/index.ts new file mode 100644 index 00000000..776ee0fe --- /dev/null +++ b/apps/website/src/components/chart/hooks/index.ts @@ -0,0 +1,2 @@ +export { useAnimations } from './use-animations' +export { useChartTooltip } from './use-chart-tooltip' diff --git a/apps/website/src/components/chart/hooks/use-animations.ts b/apps/website/src/components/chart/hooks/use-animations.ts new file mode 100644 index 00000000..28ce1354 --- /dev/null +++ b/apps/website/src/components/chart/hooks/use-animations.ts @@ -0,0 +1,99 @@ +import { config, useSpring } from '@react-spring/web' + +import type { DayType } from '../chart' +import type { TooltipData } from './use-chart-tooltip' +import type { ScaleLinear, ScaleTime } from 'd3-scale' + +type Props = { + data: DayType[] + yScale: ScaleLinear + xScale: ScaleTime + margin: { + top: number + right: number + bottom: number + left: number + } + innerHeight: number + tooltipData: TooltipData +} + +/** + * An custom hook that handles animations logic + * @param data - the data to be used in the chart + * @param margin - the margin of the chart + * @param dates - the dates of the chart + * @param innerHeight - the inner height of the chart + * @param xScale - the xScale of the chart + * @param yScale - the yScale of the chart + * @param tooltipData - the data to be used in the tooltip + + + * @returns circleSpringTotal - the spring animation for the total issues circle + * @returns circleSpringClosed - the spring animation for the closed issues circle + * @returns opacityAnimation - the spring animation for the some chart elements opacity + * @returns tooltipAnimation - the spring animation for the tooltip + * @returns drawingLineStyle - the spring animation for the drawing line style + * @returns drawingGridColumns - the spring animation for the drawing grid columns + * @returns clipPathAnimation - the spring animation for the clip path + **/ + +const useAnimations = (props: Props) => { + const { data, margin, innerHeight, tooltipData, xScale, yScale } = props + + // Define spring for circle position + const circleSpringTotal = useSpring({ + x: xScale(new Date(tooltipData?.date || '')), + y: yScale(tooltipData?.totalIssues), + config: config.gentle, + }) + + const circleSpringClosed = useSpring({ + x: xScale(new Date(tooltipData?.date)), + y: yScale(tooltipData?.closedIssues), + config: config.gentle, + }) + + const opacityAnimation = useSpring({ + opacity: data ? 1 : 0, + config: config.gentle, + delay: 200, + }) + + const tooltipAnimation = useSpring({ + x: xScale(new Date(tooltipData?.date)), + y: innerHeight + margin.top + margin.bottom, + config: config.gentle, + }) + + const [drawingLineStyle] = useSpring(() => ({ + from: { strokeDasharray: `${3000}, ${0}` }, + to: { strokeDasharray: `${0}, ${3000}` }, + reverse: true, + config: { duration: 2000 }, + })) + + const [drawingGridColumns] = useSpring(() => ({ + from: { strokeDasharray: `0, 150` }, + to: { strokeDasharray: '4,2' }, + config: { duration: 250 }, + })) + + const [clipPathAnimation] = useSpring(() => ({ + from: { clipPath: 'inset(0 100% 0 0)' }, + to: { clipPath: 'inset(0 0 0 0)' }, + config: { duration: 800 }, + })) + + return { + circleSpringTotal, + circleSpringClosed, + opacityAnimation, + tooltipAnimation, + drawingLineStyle, + drawingGridColumns, + clipPathAnimation, + } +} + +export { useAnimations } diff --git a/apps/website/src/components/chart/hooks/use-chart-tooltip.ts b/apps/website/src/components/chart/hooks/use-chart-tooltip.ts new file mode 100644 index 00000000..d7d5e09f --- /dev/null +++ b/apps/website/src/components/chart/hooks/use-chart-tooltip.ts @@ -0,0 +1,129 @@ +import { useCallback } from 'react' + +import { localPoint } from '@visx/event' +import { scaleTime } from '@visx/scale' +import { useTooltip } from '@visx/tooltip' +import { bisector, extent } from 'd3-array' + +import { getClosedIssues, getTotalIssues } from '../helpers/get-data' +import { formatDate } from '../utils/format-time' +import { getPercentage } from '../utils/get-percentage' + +import type { DayType } from '../chart' +import type { EventType } from '@visx/event/lib/types' + +type Props = { + data: DayType[] + dates: Date[] + innerWidth: number + margin: { + top: number + right: number + bottom: number + left: number + } +} + +type TooltipData = { + date: string + completedIssuesPercentage: number + openIssuesPercentage: number + totalIssues: number + openIssues: number + closedIssues: number + formattedDate: string +} + +/** + * An custom hook that handles the tooltip logic + * @param data - the data to be used in the chart + * @param margin - the margin of the chart + * @param dates - the dates of the chart + * @param innerWidth - the inner width of the chart + + * @returns tooltipData - the data to be used in the tooltip + * @returns updateTooltip - a function that updates the tooltip + * @returns hideTooltip - a function that hides the tooltip + * @returns tooltipOpen - a boolean that indicates if the tooltip is open + **/ + +const useChartTooltip = (props: Props) => { + const { data, margin, dates, innerWidth } = props + + // tooltip parameters + const { tooltipData, showTooltip, hideTooltip, tooltipOpen } = + useTooltip({ + tooltipData: { + date: '', + completedIssuesPercentage: 0, + openIssuesPercentage: 0, + totalIssues: 0, + openIssues: 0, + closedIssues: 0, + formattedDate: '', + }, + }) + + const filteredDates = dates.filter(Boolean) // filters out undefined values + + const getDate = useCallback((d: DayType) => new Date(d?.date), []) + const bisectDate = bisector((d: DayType) => new Date(d?.date)).left + + const xDomain = extent(filteredDates) as [Date, Date] + const xScale = scaleTime({ + domain: xDomain, + range: [0, innerWidth], + }) + + // Define tooltip handler + const updateTooltip = useCallback( + (event: EventType) => { + const { x } = localPoint(event) || { x: 0 } + const x0 = xScale.invert(x - margin.left) + + const index = bisectDate(data, x0, 1) + const d0 = data[index - 1] + const d1 = data[index] + let d = d0 + + if (d1 && getDate(d1)) { + d = + x0.valueOf() - getDate(d0).valueOf() > + getDate(d1).valueOf() - x0.valueOf() + ? d1 + : d0 + } + + const closedIssues = getClosedIssues(d) + const totalIssues = getTotalIssues(d) + const openIssues = totalIssues - closedIssues + + const completedIssuesPercentage = getPercentage(closedIssues, totalIssues) + + const openIssuesPercentage = getPercentage(openIssues, totalIssues) + + showTooltip({ + tooltipData: { + date: d?.date, + formattedDate: formatDate(getDate(d)), + completedIssuesPercentage, + openIssuesPercentage, + closedIssues, + totalIssues, + openIssues, + }, + }) + }, + [xScale, margin.left, bisectDate, data, getDate, showTooltip] + ) + + return { + tooltipData: tooltipData!, + hideTooltip, + updateTooltip, + tooltipOpen, + } +} + +export { useChartTooltip } +export type { TooltipData, Props as UseChartTooltipProps } diff --git a/apps/website/src/components/chart/utils/format-time.ts b/apps/website/src/components/chart/utils/format-time.ts new file mode 100644 index 00000000..918041cf --- /dev/null +++ b/apps/website/src/components/chart/utils/format-time.ts @@ -0,0 +1,13 @@ +import { timeFormat } from 'd3-time-format' + +/** + * Util functions that formats a date + * formatDate @returns a string with the format 'MMM dd yyyy' - Ex: Jan 01 2021 + **/ +export const formatDate = timeFormat('%b %d %Y') + +/** + * Util functions that formats a date + * format @returns a string with the format 'dd MMM' - Ex: 01 Jan + **/ +export const format = timeFormat('%d %b') diff --git a/apps/website/src/components/chart/utils/get-percentage.ts b/apps/website/src/components/chart/utils/get-percentage.ts new file mode 100644 index 00000000..c174e4c2 --- /dev/null +++ b/apps/website/src/components/chart/utils/get-percentage.ts @@ -0,0 +1,8 @@ +/** + * An util function that gets the percentage of a value from a total + * @param value - the value to calculate the percentage + * @param total - the total value + **/ + +export const getPercentage = (value: number, total: number): number => + Math.round((value / total) * 100) diff --git a/apps/website/src/components/epic-overview.tsx b/apps/website/src/components/epic-overview.tsx index 59955691..fdf686e5 100644 --- a/apps/website/src/components/epic-overview.tsx +++ b/apps/website/src/components/epic-overview.tsx @@ -1,6 +1,98 @@ +import { useEffect, useState } from 'react' + import { Tag, Text } from '@status-im/components' import { OpenIcon } from '@status-im/icons' +import { Chart } from './chart/chart' + +const DATA = [ + { + date: '2022-01-25', + open_issues: 100, + closed_issues: 2, + }, + { + date: '2022-01-26', + open_issues: 100, + closed_issues: 10, + }, + { + date: '2022-01-27', + open_issues: 100, + closed_issues: 20, + }, + { + date: '2022-01-28', + open_issues: 90, + closed_issues: 30, + }, + { + date: '2022-01-29', + open_issues: 80, + closed_issues: 40, + }, + { + date: '2022-01-30', + open_issues: 40, + closed_issues: 80, + }, + { + date: '2022-01-31', + open_issues: 30, + closed_issues: 90, + }, + { + date: '2022-02-01', + open_issues: 25, + closed_issues: 95, + }, + { + date: '2022-02-02', + open_issues: 20, + closed_issues: 98, + }, + { + date: '2022-02-03', + open_issues: 10, + closed_issues: 130, + }, + { + date: '2022-02-04', + open_issues: 10, + closed_issues: 140, + }, + { + date: '2022-02-05', + open_issues: 10, + closed_issues: 150, + }, + { + date: '2022-02-06', + open_issues: 10, + closed_issues: 160, + }, + { + date: '2022-02-07', + open_issues: 10, + closed_issues: 180, + }, + { + date: '2022-02-08', + open_issues: 10, + closed_issues: 190, + }, + { + date: '2022-02-09', + open_issues: 10, + closed_issues: 200, + }, + { + date: '2022-02-10', + open_issues: 0, + closed_issues: 220, + }, +] + type Props = { title: string description: string @@ -10,8 +102,20 @@ type Props = { export const EpicOverview = (props: Props) => { const { title, description, fullscreen } = props + // Simulating loading state + const [isLoading, setIsLoading] = useState(true) + useEffect(() => { + const timeout = setTimeout(() => { + setIsLoading(false) + }, 2000) + + return () => { + clearTimeout(timeout) + } + }, []) + return ( -
    +
    {title} @@ -25,7 +129,7 @@ export const EpicOverview = (props: Props) => {
    - +
    @@ -41,750 +145,3 @@ export const EpicOverview = (props: Props) => {
    ) } - -// USE https://airbnb.io/visx/areas -const ChartPreview = () => ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -) diff --git a/apps/website/src/styles/app.css b/apps/website/src/styles/app.css new file mode 100644 index 00000000..81db796a --- /dev/null +++ b/apps/website/src/styles/app.css @@ -0,0 +1,36 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +html, +body, +#__next { + height: 100%; + overscroll-behavior: none; + user-select: none; + color: #000; +} + +*::selection { + color: #fff; + background: hsla(229, 71%, 57%, 1); +} + +#app { + position: relative; + isolation: isolate; + height: 100%; +} + +/* Animation for skeleton placeholder */ +@keyframes gradient { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} diff --git a/packages/components/.storybook/preview.tsx b/packages/components/.storybook/preview.tsx index 16361664..015ce459 100644 --- a/packages/components/.storybook/preview.tsx +++ b/packages/components/.storybook/preview.tsx @@ -4,7 +4,6 @@ import type { Preview } from '@storybook/react' import { Provider, ToastContainer } from '../src' import './reset.css' -import './components.css' // export const parameters: Parameters = { // actions: { argTypesRegex: '^on[A-Z].*' }, diff --git a/packages/components/.storybook/components.css b/packages/components/src/skeleton/skeleton.css similarity index 100% rename from packages/components/.storybook/components.css rename to packages/components/src/skeleton/skeleton.css diff --git a/packages/components/src/skeleton/skeleton.tsx b/packages/components/src/skeleton/skeleton.tsx index b96a4064..f7019f2d 100644 --- a/packages/components/src/skeleton/skeleton.tsx +++ b/packages/components/src/skeleton/skeleton.tsx @@ -1,3 +1,5 @@ +import './skeleton.css' + import { Stack, useTheme } from '@tamagui/core' import type { RadiusTokens } from '../tokens' diff --git a/yarn.lock b/yarn.lock index 58381695..26883867 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4437,6 +4437,52 @@ dependencies: nanoid "^3.1.23" +"@react-spring/animated@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.7.2.tgz#0119db8075e91d693ec45c42575541e01b104a70" + integrity sha512-ipvleJ99ipqlnHkz5qhSsgf/ny5aW0ZG8Q+/2Oj9cI7LCc7COdnrSO6V/v8MAX3JOoQNzfz6dye2s5Pt5jGaIA== + dependencies: + "@react-spring/shared" "~9.7.2" + "@react-spring/types" "~9.7.2" + +"@react-spring/core@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.7.2.tgz#804ebadee45a6adff00886454d6f1c5d97ee219d" + integrity sha512-fF512edZT/gKVCA90ZRxfw1DmELeVwiL4OC2J6bMUlNr707C0h4QRoec6DjzG27uLX2MvS1CEatf9KRjwZR9/w== + dependencies: + "@react-spring/animated" "~9.7.2" + "@react-spring/rafz" "~9.7.2" + "@react-spring/shared" "~9.7.2" + "@react-spring/types" "~9.7.2" + +"@react-spring/rafz@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.7.2.tgz#77e7088c215e05cf893851cd87ceb40d89f2a7d7" + integrity sha512-kDWMYDQto3+flkrX3vy6DU/l9pxQ4TVW91DglQEc11iDc7shF4+WVDRJvOVLX+xoMP7zyag1dMvlIgvQ+dvA/A== + +"@react-spring/shared@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.7.2.tgz#b8485617bdcc9f6348b245922051fb534e07c566" + integrity sha512-6U9qkno+9DxlH5nSltnPs+kU6tYKf0bPLURX2te13aGel8YqgcpFYp5Av8DcN2x3sukinAsmzHUS/FRsdZMMBA== + dependencies: + "@react-spring/rafz" "~9.7.2" + "@react-spring/types" "~9.7.2" + +"@react-spring/types@~9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.7.2.tgz#e04dd72755d88b0e3163ba143ecd8ba78b68a5b0" + integrity sha512-GEflx2Ex/TKVMHq5g5MxQDNNPNhqg+4Db9m7+vGTm8ttZiyga7YQUF24shgRNebKIjahqCuei16SZga8h1pe4g== + +"@react-spring/web@^9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.7.2.tgz#76e53dd24033764c3062f9927f88b0f3194688d4" + integrity sha512-7qNc7/5KShu2D05x7o2Ols2nUE7mCKfKLaY2Ix70xPMfTle1sZisoQMBFgV9w/fSLZlHZHV9P0uWJqEXQnbV4Q== + dependencies: + "@react-spring/animated" "~9.7.2" + "@react-spring/core" "~9.7.2" + "@react-spring/shared" "~9.7.2" + "@react-spring/types" "~9.7.2" + "@rollup/plugin-babel@^6.0.3": version "6.0.3" resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-6.0.3.tgz#07ccde15de278c581673034ad6accdb4a153dfeb" @@ -6699,6 +6745,86 @@ dependencies: "@types/node" "*" +"@types/d3-array@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.4.tgz#44eebe40be57476cad6a0cd6a85b0f57d54185a2" + integrity sha512-nwvEkG9vYOc0Ic7G7kwgviY4AQlTfYGIZ0fqB7CQHXGyYM6nO7kJh5EguSNA3jfh4rq7Sb7eMVq8isuvg2/miQ== + +"@types/d3-cloud@1.2.5": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@types/d3-cloud/-/d3-cloud-1.2.5.tgz#0300bedc826aacd505ae6c41c5f8c4ab75c45135" + integrity sha512-vEIER9DsEBUOdpRiwCh3n1qE+cV6h4e1LhxhY2sLt+m8LPNAIkOOhTlqk0JDiBwD+ZPM8ynFAOU3AuPuVYBFBA== + dependencies: + "@types/d3" "^3" + +"@types/d3-color@^1": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-1.4.2.tgz#944f281d04a0f06e134ea96adbb68303515b2784" + integrity sha512-fYtiVLBYy7VQX+Kx7wU/uOIkGQn8aAEY8oWMoyja3N4dLd8Yf6XgSIR/4yWvMuveNOH5VShnqCgRqqh/UNanBA== + +"@types/d3-geo@^1.11.1": + version "1.12.4" + resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-1.12.4.tgz#7fbd90b6fdb25e34ce4f557c0de73360d662850f" + integrity sha512-lNDaAuOaML6w2d1XE0Txr5YOXLBQSF1q2IU6eXh/u1TTPQSm2Ah+TMIub1+CIMq8J/7DOzi5Cr8/yHqjNvqLKA== + dependencies: + "@types/geojson" "*" + +"@types/d3-hierarchy@^1.1.6": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz#50657f420d565a06c0b950a4b82eee0a369f2dea" + integrity sha512-AbStKxNyWiMDQPGDguG2Kuhlq1Sv539pZSxYbx4UZeYkutpPwXCcgyiRrlV4YH64nIOsKx7XVnOMy9O7rJsXkg== + +"@types/d3-interpolate@^1.3.1": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-1.4.2.tgz#88902a205f682773a517612299a44699285eed7b" + integrity sha512-ylycts6llFf8yAEs1tXzx2loxxzDZHseuhPokrqKprTQSTcD3JbJI1omZP1rphsELZO3Q+of3ff0ZS7+O6yVzg== + dependencies: + "@types/d3-color" "^1" + +"@types/d3-path@^1", "@types/d3-path@^1.0.8": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-1.0.9.tgz#73526b150d14cd96e701597cbf346cfd1fd4a58c" + integrity sha512-NaIeSIBiFgSC6IGUBjZWcscUJEq7vpVu7KthHN8eieTV9d9MqkSOZLH4chq1PmcKy06PNe3axLeKmRIyxJ+PZQ== + +"@types/d3-random@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/d3-random/-/d3-random-2.2.1.tgz#551edbb71cb317dea2cf9c76ebe059d311eefacb" + integrity sha512-5vvxn6//poNeOxt1ZwC7QU//dG9QqABjy1T7fP/xmFHY95GnaOw3yABf29hiu5SR1Oo34XcpyHFbzod+vemQjA== + +"@types/d3-scale@^3.3.0": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-3.3.2.tgz#18c94e90f4f1c6b1ee14a70f14bfca2bd1c61d06" + integrity sha512-gGqr7x1ost9px3FvIfUMi5XA/F/yAf4UkUDtdQhpH92XCT0Oa7zkkRzY61gPVJq+DxpHn/btouw5ohWkbBsCzQ== + dependencies: + "@types/d3-time" "^2" + +"@types/d3-shape@^1.3.1": + version "1.3.8" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-1.3.8.tgz#c3c15ec7436b4ce24e38de517586850f1fea8e89" + integrity sha512-gqfnMz6Fd5H6GOLYixOZP/xlrMtJms9BaS+6oWxTKHNqPGZ93BkWWupQSCYm6YHqx6h9wjRupuJb90bun6ZaYg== + dependencies: + "@types/d3-path" "^1" + +"@types/d3-time-format@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/d3-time-format/-/d3-time-format-4.0.0.tgz#ee7b6e798f8deb2d9640675f8811d0253aaa1946" + integrity sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw== + +"@types/d3-time@^2", "@types/d3-time@^2.0.0": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-2.1.1.tgz#743fdc821c81f86537cbfece07093ac39b4bc342" + integrity sha512-9MVYlmIgmRR31C5b4FVSWtuMmBHh2mOWQYfl7XAYOa8dsnb7iEmUmRSWSFgXFtkjxO65d7hTUHQC+RhR/9IWFg== + +"@types/d3-voronoi@^1.1.9": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@types/d3-voronoi/-/d3-voronoi-1.1.9.tgz#7bbc210818a3a5c5e0bafb051420df206617c9e5" + integrity sha512-DExNQkaHd1F3dFPvGA/Aw2NGyjMln6E9QzsiqOcBgnE+VInYnFBHBBySbZQts6z6xD+5jTfKCP7M4OqMyVjdwQ== + +"@types/d3@^3": + version "3.5.47" + resolved "https://registry.yarnpkg.com/@types/d3/-/d3-3.5.47.tgz#b81042fcb0195c583fc037bc857d161469a7d175" + integrity sha512-VkWIQoZXLFdcBGe5pdBKJmTU3fmpXvo/KV6ixvTzOMl1yJ2hbTXpfvsziag0kcaerPDwas2T0vxojwQG3YwivQ== + "@types/detect-port@^1.3.0": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/detect-port/-/detect-port-1.3.2.tgz#8c06a975e472803b931ee73740aeebd0a2eb27ae" @@ -6768,6 +6894,11 @@ dependencies: "@types/node" "*" +"@types/geojson@*": + version "7946.0.10" + resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249" + integrity sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA== + "@types/glob@^7.1.3": version "7.2.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" @@ -6849,6 +6980,11 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa" integrity sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ== +"@types/lodash@^4.14.172": + version "4.14.194" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.194.tgz#b71eb6f7a0ff11bff59fc987134a093029258a76" + integrity sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g== + "@types/long@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" @@ -6952,7 +7088,7 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== -"@types/react-dom@18.0.11", "@types/react-dom@^18.0.11": +"@types/react-dom@*", "@types/react-dom@18.0.11", "@types/react-dom@^18.0.11": version "18.0.11" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.11.tgz#321351c1459bc9ca3d216aefc8a167beec334e33" integrity sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw== @@ -7202,6 +7338,417 @@ "@urql/core" ">=2.3.1" wonka "^4.0.14" +"@use-gesture/core@10.2.26": + version "10.2.26" + resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.2.26.tgz#c2fc4aa7d36cee7319a98a898b0698c66b01663e" + integrity sha512-NyFpQ3iID9iFBROXyyvU1D0NK+t+dP+WAVByhCvqHUenpxLD2NlRLVRpoK3XGGwksr6mU3PvZ2Nm4q0q+gLJPA== + +"@use-gesture/react@^10.0.0-beta.22": + version "10.2.26" + resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.2.26.tgz#593549fed30ebcac71cfd197993eaede0795c098" + integrity sha512-0QhaE5mhaQbFlip4MX7n1nwCX8gax6Da1LsP2fZ/BU6xW9zyEmV6NX7DPelDxq1rr2NiBJh30vx9RIp80YeA/A== + dependencies: + "@use-gesture/core" "10.2.26" + +"@visx/annotation@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/annotation/-/annotation-2.18.0.tgz#6fe29e3bd33606d58fb63603d01c7a4a1bf36561" + integrity sha512-dEuZ4jlyJQ0dJ/tOhmP9bJP+GTw7/2EnmIKms1z/icoD3rCYA9bLjHq9J/3mNzvMkw/2+whTC/cxpBZyXUeLXA== + dependencies: + "@types/react" "*" + "@visx/drag" "2.17.0" + "@visx/group" "2.17.0" + "@visx/point" "2.17.0" + "@visx/shape" "2.18.0" + "@visx/text" "2.17.0" + classnames "^2.3.1" + prop-types "^15.5.10" + react-use-measure "^2.0.4" + +"@visx/axis@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/axis/-/axis-2.18.0.tgz#9175e9d969df420592082b1ea64c16422377b389" + integrity sha512-iBMObSKHOHDZbuVXsdVLmAjLE5jCN1Ls3XI57v3yuf+qZ327mdPSliSOyOxhvRdaNDYPLSQj+P1nKan+04wJiQ== + dependencies: + "@types/react" "*" + "@visx/group" "2.17.0" + "@visx/point" "2.17.0" + "@visx/scale" "2.18.0" + "@visx/shape" "2.18.0" + "@visx/text" "2.17.0" + classnames "^2.3.1" + prop-types "^15.6.0" + +"@visx/bounds@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/bounds/-/bounds-2.17.0.tgz#2585be71bc82032ad3e1456b34b2f2c17ad34e69" + integrity sha512-XsoyTAyCm+DZbrPgP3IZFZAcNqBmXFBLSep04TqnrEA3hf16GxIzcpaGe+hAVhPg5yzBdjc7tLk6s0h5F44niA== + dependencies: + "@types/react" "*" + "@types/react-dom" "*" + prop-types "^15.5.10" + +"@visx/brush@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/brush/-/brush-2.18.0.tgz#847bab691166a0ced187d49c1459a80845925d28" + integrity sha512-9hTi2h/rq+wGtGW8ntkOjh52TWl5S8IngApcegWH2jljOY++1LLQOXBXj62MO1n/RSfH45EOPS4M+fBRU/JAZA== + dependencies: + "@visx/drag" "2.17.0" + "@visx/event" "2.17.0" + "@visx/group" "2.17.0" + "@visx/scale" "2.18.0" + "@visx/shape" "2.18.0" + classnames "^2.3.1" + prop-types "^15.6.1" + +"@visx/clip-path@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/clip-path/-/clip-path-2.17.0.tgz#25156ec56d074635601c60b1f5dec45dc7e52e15" + integrity sha512-kxSWJEmycPDdM+Nj8ka9k1jy/fCs1DmmA6tVE0QmEnaKChqwTWvX8ugb2I+7Ijb349JzLjLYB1vRBGCv2L60pQ== + dependencies: + "@types/react" "*" + prop-types "^15.5.10" + +"@visx/curve@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/curve/-/curve-2.17.0.tgz#9b4c87dd0d10a62a0f85d5a72e4c0400316df9bf" + integrity sha512-8Fw2ZalgYbpeoelLqTOmMs/wD8maSKsKS9rRIwmHZ0O0XxY8iG9oVYbD4CLWzf/uFWCY6+qofk4J1g9BWQSXJQ== + dependencies: + "@types/d3-shape" "^1.3.1" + d3-shape "^1.0.6" + +"@visx/drag@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/drag/-/drag-2.17.0.tgz#22e8e06d7dfe9e9527e7e1d4dd5ceb0195898c2b" + integrity sha512-k6PNOmL9Q1jiz+sCzxiV+Ue41EOU597WBPEZQd9baL08OQlFsYLxT95OpqQvZwlU1aHHr3hXxg4W6LtUCcUrNQ== + dependencies: + "@types/react" "*" + "@visx/event" "2.17.0" + "@visx/point" "2.17.0" + prop-types "^15.5.10" + +"@visx/event@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/event/-/event-2.17.0.tgz#220c7674505e0d7a55f36bce9575482a7fa7dc23" + integrity sha512-fg2UWo89RgKgWWnnqI+i7EF8Ry+3CdMHTND4lo4DyJvcZZUCOwhxCHMQ4/PHW0EAUfxI51nGadcE1BcEVR5zWw== + dependencies: + "@types/react" "*" + "@visx/point" "2.17.0" + +"@visx/geo@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/geo/-/geo-2.17.0.tgz#69866342375364b53882d4f5114e3adfb6317c9c" + integrity sha512-/MXXXxy5XDmwGLuRQwHxazaL1k2iymayVjmHu32vi+P7G/wahGqvWfwkdbw5CKnOMuPeEeM40CvEWQY8H6VXxg== + dependencies: + "@types/d3-geo" "^1.11.1" + "@types/geojson" "*" + "@types/react" "*" + "@visx/group" "2.17.0" + classnames "^2.3.1" + d3-geo "^1.11.3" + prop-types "^15.5.10" + +"@visx/glyph@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/glyph/-/glyph-2.17.0.tgz#1e10c2223db45d106b1526f744981431f895a2c4" + integrity sha512-/EnygQrlgxqH/dOV2jIAgis7mb18GOvnF2ZF/nPWvSKCetObqeQnQZFmjzYS3S2leW/nNpOFXj5dSWBU07LhjA== + dependencies: + "@types/d3-shape" "^1.3.1" + "@types/react" "*" + "@visx/group" "2.17.0" + classnames "^2.3.1" + d3-shape "^1.2.0" + prop-types "^15.6.2" + +"@visx/gradient@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/gradient/-/gradient-2.17.0.tgz#8c1113f66703b48ee2d4fc064d7ff6dfc701094c" + integrity sha512-3vyMzSR5iSo8+nKOx+bQZpFXqFGVzCrRbuStxTH4Ag0KFATOYnjCsypjD+gc2DEVzkarVGy0V9kRfFIH09r8Fg== + dependencies: + "@types/react" "*" + prop-types "^15.5.7" + +"@visx/grid@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/grid/-/grid-2.18.0.tgz#ae68e975d4b203a626ddba3a39d67a135816d6be" + integrity sha512-bmOowI5QA0R1KgNKxj5y+Belj5MbUz+RRW2BxTsXa7NbDV6IsA7H4l+kj3DDldRi7Q5SVm9zpfwWXNIBAhiFdA== + dependencies: + "@types/react" "*" + "@visx/curve" "2.17.0" + "@visx/group" "2.17.0" + "@visx/point" "2.17.0" + "@visx/scale" "2.18.0" + "@visx/shape" "2.18.0" + classnames "^2.3.1" + prop-types "^15.6.2" + +"@visx/group@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/group/-/group-2.17.0.tgz#b349fd6507e56fcb43d0b067d728df4ab329ca2e" + integrity sha512-60Y2dIKRh3cp/Drpq//wM067ZNrnCcvFCXufPgIihv0Ix8O7oMsYxu3ch4XUMjks+U2IAZQr5Dnc+C9sTQFkhw== + dependencies: + "@types/react" "*" + classnames "^2.3.1" + prop-types "^15.6.2" + +"@visx/heatmap@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/heatmap/-/heatmap-2.17.0.tgz#10ae00a48d37c3f1cdc9a224bd5caf5e285e5c31" + integrity sha512-BHQrd9hOIzoRLEk8DK3H2Vc4K7GjN6uHeJCghSW352OxhNga+5SpW4nHyoZxIdQLtl1m5bniGaypjQKlRcBCOQ== + dependencies: + "@types/react" "*" + "@visx/group" "2.17.0" + classnames "^2.3.1" + prop-types "^15.6.1" + +"@visx/hierarchy@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/hierarchy/-/hierarchy-2.17.0.tgz#1ec1a4e236f13685a7c3dd76d04a3d8db7b83502" + integrity sha512-5JYrS0JHl66JnhkVPv1XMkBnl8vBakODSZqR8Tf2VxmcZitG2W4tEUNulApBznSqYHuT49YsNxlgAER/I8FZjg== + dependencies: + "@types/d3-hierarchy" "^1.1.6" + "@types/react" "*" + "@visx/group" "2.17.0" + classnames "^2.3.1" + d3-hierarchy "^1.1.4" + prop-types "^15.6.1" + +"@visx/legend@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/legend/-/legend-2.18.0.tgz#1358ec29cb628ef9594ca5f34e91771536f9205b" + integrity sha512-x6RfW6NOV+I9bIx45MQlCIxDR89KdA0Y4rPrVFDdq9KSf+DICaIQw97ksGsixxQwEuiRfqGTtM6F/PXCfEx/zQ== + dependencies: + "@types/react" "*" + "@visx/group" "2.17.0" + "@visx/scale" "2.18.0" + classnames "^2.3.1" + prop-types "^15.5.10" + +"@visx/marker@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/marker/-/marker-2.18.0.tgz#1be8216cd6412b88163713759712e782962a8c5d" + integrity sha512-29qEbw4SRbKD1HpKpHbou0lsu7Mfvl7a+K/M/U99/CSwLnKaLJ5zaZ1hG+sDZ5rW9efPKef1bFjqgWqgjZG46w== + dependencies: + "@types/react" "*" + "@visx/group" "2.17.0" + "@visx/shape" "2.18.0" + classnames "^2.3.1" + prop-types "^15.6.2" + +"@visx/mock-data@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/mock-data/-/mock-data-2.17.0.tgz#55146962abfb388faf3a5d6775a67c45e83f6dbd" + integrity sha512-l+9tcJAZ+H5mtXaGbHUqgmo1b3Hcq+k6aIWmZt6VGgvPBFK3Rn68BORP8My+OA/CgMG3/ZNJBhJxLKxNN5Hkjw== + dependencies: + "@types/d3-random" "^2.2.0" + d3-random "^2.2.2" + +"@visx/network@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/network/-/network-2.17.0.tgz#d5273ab303392860157067be9b3505baa9a3a527" + integrity sha512-TlUCeSnFaGetzai3CiCG5n3DULfTKMsle6Cx9EoX4o/Hz4LsUsCb1lyQLz/3oKwxOyN/787vuMBUXqg16ygBOQ== + dependencies: + "@types/react" "*" + "@visx/group" "2.17.0" + classnames "^2.3.1" + prop-types "^15.6.2" + +"@visx/pattern@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/pattern/-/pattern-2.17.0.tgz#c00e7f80fa3d9100046d7480222679c8d92d9ae0" + integrity sha512-Mt1BXj3eQA+/6SeyxKEZvEUs43N4RHrnoISoQYctVJ+H8EcgfRyQZnxQRDqmY++YTW+VfXyJEGVU4Ix8Yzd1tA== + dependencies: + "@types/react" "*" + classnames "^2.3.1" + prop-types "^15.5.10" + +"@visx/point@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/point/-/point-2.17.0.tgz#c11f1efee5241bcd612a29f3b3099cb435c9604e" + integrity sha512-fUdGQBLGaSVbFTbQ6k+1nPisbqYjTjAdo9FhlwLd3W3uyXN/39Sx2z3N2579sVNBDzmCKdYNQIU0HC+/3Vqo6w== + +"@visx/react-spring@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/react-spring/-/react-spring-2.18.0.tgz#c19c8f64213dae9d62147ae1f99321f6c63c1c91" + integrity sha512-tTLqddFAlNZc7QvB7aWp4mC6z6NYbrTEU3/OyBplqNUwaI1W5S0se3fYf6xOxC88EbNoqCC7805ym2XoznknoQ== + dependencies: + "@types/react" "*" + "@visx/axis" "2.18.0" + "@visx/grid" "2.18.0" + "@visx/scale" "2.18.0" + "@visx/text" "2.17.0" + classnames "^2.3.1" + prop-types "^15.6.2" + +"@visx/responsive@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/responsive/-/responsive-2.17.0.tgz#8a31f016a270234bfecf25fb066f30d19784ddc7" + integrity sha512-3dY2shGbQnoknIRv3Vfnwsy3ZA8Q5Q/rYnTLiokWChYRfNC8NMPoX9mprEeb/gMAxtKjaLn3zcCgd8R+eetxIQ== + dependencies: + "@juggle/resize-observer" "^3.3.1" + "@types/lodash" "^4.14.172" + "@types/react" "*" + lodash "^4.17.21" + prop-types "^15.6.1" + +"@visx/scale@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/scale/-/scale-2.18.0.tgz#b78054e68ac8de49f0abeea0c60bb0bd14dec492" + integrity sha512-clH8HFblMlCuHvUjGRwenvbY1w9YXHU9fPl91Vbtd5bdM9xAN0Lo2+cgV46cvaX3YpnyVb4oNhlbPCBu3h6Rhw== + dependencies: + "@types/d3-interpolate" "^1.3.1" + "@types/d3-scale" "^3.3.0" + "@types/d3-time" "^2.0.0" + d3-interpolate "^1.4.0" + d3-scale "^3.3.0" + d3-time "^2.1.1" + +"@visx/shape@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/shape/-/shape-2.18.0.tgz#0d7202ca9e722ed9360e1b76f6de7b2748511d2a" + integrity sha512-kVSEjnzswQMyFDa/IXE7K+WsAkl91xK6A4W6MbGfcUhfQn+AP0GorvotW7HZGjkIlbmuLl14+vRktDo5jqS/og== + dependencies: + "@types/d3-path" "^1.0.8" + "@types/d3-shape" "^1.3.1" + "@types/lodash" "^4.14.172" + "@types/react" "*" + "@visx/curve" "2.17.0" + "@visx/group" "2.17.0" + "@visx/scale" "2.18.0" + classnames "^2.3.1" + d3-path "^1.0.5" + d3-shape "^1.2.0" + lodash "^4.17.21" + prop-types "^15.5.10" + +"@visx/text@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/text/-/text-2.17.0.tgz#e65aa8a202ce9cfdcbd898bb0afd6253ccea6a40" + integrity sha512-Eu6b8SMI+LU4O6H4l/QhCa7c4GtDTQO6jhSYuU70pdTST1Bm74nImPGekG2xDW3uxaLlkb8fDpvXag0Z7v+vlQ== + dependencies: + "@types/lodash" "^4.14.172" + "@types/react" "*" + classnames "^2.3.1" + lodash "^4.17.21" + prop-types "^15.7.2" + reduce-css-calc "^1.3.0" + +"@visx/threshold@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/threshold/-/threshold-2.18.0.tgz#7c41e1c16fac845645fa547f1ca85e5f2136bc24" + integrity sha512-pD+7XQuh8ZwHQBEriMJD1xk9G86HokuJ6E34aYxfDLJgPuVxHYjtzRHc9lLDCMiexA4enY1FyQf9L2ruTkszmw== + dependencies: + "@types/react" "*" + "@visx/clip-path" "2.17.0" + "@visx/shape" "2.18.0" + classnames "^2.3.1" + prop-types "^15.5.10" + +"@visx/tooltip@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/tooltip/-/tooltip-2.17.0.tgz#e5e39a62795d2f6c7d2a1472e7af092005374106" + integrity sha512-+dMHURP9NqSFZLomMUnoVYjRs+I2qcOw1yYvLtTp/4GUAFRMSUJoSJeuLwng1VBIgCEB95xuQ95NgGID4qzPxA== + dependencies: + "@types/react" "*" + "@visx/bounds" "2.17.0" + classnames "^2.3.1" + prop-types "^15.5.10" + react-use-measure "^2.0.4" + +"@visx/visx@^2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/visx/-/visx-2.18.0.tgz#a4b23a8883856470672edae023fc079e9f8410cb" + integrity sha512-PGpe1haqBXriEVnCHwnGhd0E0yinA3bKnMKf6PE/Ud8pOi3vpfeWxHO3jnrpZrC+mP+yG8JrsevBsgTCYaVG8A== + dependencies: + "@visx/annotation" "2.18.0" + "@visx/axis" "2.18.0" + "@visx/bounds" "2.17.0" + "@visx/brush" "2.18.0" + "@visx/clip-path" "2.17.0" + "@visx/curve" "2.17.0" + "@visx/drag" "2.17.0" + "@visx/event" "2.17.0" + "@visx/geo" "2.17.0" + "@visx/glyph" "2.17.0" + "@visx/gradient" "2.17.0" + "@visx/grid" "2.18.0" + "@visx/group" "2.17.0" + "@visx/heatmap" "2.17.0" + "@visx/hierarchy" "2.17.0" + "@visx/legend" "2.18.0" + "@visx/marker" "2.18.0" + "@visx/mock-data" "2.17.0" + "@visx/network" "2.17.0" + "@visx/pattern" "2.17.0" + "@visx/point" "2.17.0" + "@visx/responsive" "2.17.0" + "@visx/scale" "2.18.0" + "@visx/shape" "2.18.0" + "@visx/text" "2.17.0" + "@visx/threshold" "2.18.0" + "@visx/tooltip" "2.17.0" + "@visx/voronoi" "2.17.0" + "@visx/wordcloud" "2.17.0" + "@visx/xychart" "2.18.0" + "@visx/zoom" "2.17.0" + +"@visx/voronoi@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/voronoi/-/voronoi-2.17.0.tgz#4c79cd200453654fd3d030a4fe599e84da9ea065" + integrity sha512-enwuidtUPntdEcMZ2PyGXaFFP87KX8YYd/pCXQ6TQ6hJfnkMe3hlwLs5skv8gijz1oHy9PkESVqgrFPb25IICA== + dependencies: + "@types/d3-voronoi" "^1.1.9" + "@types/react" "*" + classnames "^2.3.1" + d3-voronoi "^1.1.2" + prop-types "^15.6.1" + +"@visx/wordcloud@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/wordcloud/-/wordcloud-2.17.0.tgz#5fe8e484baaf1abc944b5d4b93667e2e51cde4e7" + integrity sha512-HLatkmBlbHERC+ANuZMLMzP7PiGYtX1NPyQVzEjacsBMsQEruSFDG8P7c5xrsNTIQM1+k8KMkitADvN4iPxftw== + dependencies: + "@types/d3-cloud" "1.2.5" + "@visx/group" "2.17.0" + d3-cloud "^1.2.5" + +"@visx/xychart@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@visx/xychart/-/xychart-2.18.0.tgz#db87846d54f1537e4b8ddcd89a02970ae3a38642" + integrity sha512-IMCyuoZT4ky/CthtmJMyyB6nyLa1jdgW3XBx3UPCqWrQVkOH38tHNVFTHEgLkL0TyRKroK82F+JWD3yrc1B2Xw== + dependencies: + "@types/lodash" "^4.14.172" + "@types/react" "*" + "@visx/annotation" "2.18.0" + "@visx/axis" "2.18.0" + "@visx/event" "2.17.0" + "@visx/glyph" "2.17.0" + "@visx/grid" "2.18.0" + "@visx/react-spring" "2.18.0" + "@visx/responsive" "2.17.0" + "@visx/scale" "2.18.0" + "@visx/shape" "2.18.0" + "@visx/text" "2.17.0" + "@visx/tooltip" "2.17.0" + "@visx/voronoi" "2.17.0" + classnames "^2.3.1" + d3-array "^2.6.0" + d3-interpolate-path "2.2.1" + d3-shape "^2.0.0" + lodash "^4.17.21" + mitt "^2.1.0" + prop-types "^15.6.2" + +"@visx/zoom@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@visx/zoom/-/zoom-2.17.0.tgz#e7c0184ce372fca45825e71e472b5445de230468" + integrity sha512-C/FxGzzV3X05+1wgKoHnsfNma5wy17DwThEhUK3/wo8nc7Fsb7dtuQn3HOzVpuqa52LbscUBJFi2Rxv79VykQQ== + dependencies: + "@types/react" "*" + "@use-gesture/react" "^10.0.0-beta.22" + "@visx/event" "2.17.0" + prop-types "^15.6.2" + "@vitejs/plugin-react-swc@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.2.0.tgz#7c4f6e116a296c27f680d05750f9dbf798cf7709" @@ -7900,6 +8447,11 @@ babel-preset-fbjs@^3.4.0: "@babel/plugin-transform-template-literals" "^7.0.0" babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" +balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + integrity sha512-STw03mQKnGUYtoNjmowo4F2cRmIIxYEGiMsjjwla/u5P1lxadj/05WkNaFjNiKTgJkj8KiXbgAiRTmcQRwQNtg== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -8427,6 +8979,11 @@ class-variance-authority@^0.6.0: dependencies: clsx "1.2.1" +classnames@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" + integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw== + clean-css@^5.2.2: version "5.3.2" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224" @@ -9013,6 +9570,156 @@ csv@^5.5.0: csv-stringify "^5.6.5" stream-transform "^2.1.3" +d3-array@1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" + integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== + +d3-array@2, d3-array@^2.3.0, d3-array@^2.6.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" + integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== + dependencies: + internmap "^1.0.0" + +"d3-array@2 - 3", d3-array@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.3.tgz#39f1f4954e4a09ff69ac597c2d61906b04e84740" + integrity sha512-JRHwbQQ84XuAESWhvIPaUV4/1UYTBOLiOPGWqgFDHZS1D5QN9c57FbH3QpEnQMYiOXNzKUQyGTZf+EVO7RT5TQ== + dependencies: + internmap "1 - 2" + +d3-cloud@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/d3-cloud/-/d3-cloud-1.2.5.tgz#3e91564f2d27fba47fcc7d812eb5081ea24c603d" + integrity sha512-4s2hXZgvs0CoUIw31oBAGrHt9Kt/7P9Ik5HIVzISFiWkD0Ga2VLAuO/emO/z1tYIpE7KG2smB4PhMPfFMJpahw== + dependencies: + d3-dispatch "^1.0.3" + +d3-color@1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" + integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== + +"d3-color@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" + integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== + +d3-dispatch@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" + integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA== + +"d3-format@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-2.0.0.tgz#a10bcc0f986c372b729ba447382413aabf5b0767" + integrity sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA== + +d3-geo@^1.11.3: + version "1.12.1" + resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f" + integrity sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg== + dependencies: + d3-array "1" + +d3-hierarchy@^1.1.4: + version "1.1.9" + resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83" + integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ== + +d3-interpolate-path@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/d3-interpolate-path/-/d3-interpolate-path-2.2.1.tgz#fd8ff20a90aff3f380bcd1c15305e7b531e55d07" + integrity sha512-6qLLh/KJVzls0XtMsMpcxhqMhgVEN7VIbR/6YGZe2qlS8KDgyyVB20XcmGnDyB051HcefQXM/Tppa9vcANEA4Q== + +"d3-interpolate@1.2.0 - 2": + version "2.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163" + integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== + dependencies: + d3-color "1 - 2" + +d3-interpolate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987" + integrity sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA== + dependencies: + d3-color "1" + +d3-path@1, d3-path@^1.0.5: + version "1.0.9" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" + integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== + +"d3-path@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-2.0.0.tgz#55d86ac131a0548adae241eebfb56b4582dd09d8" + integrity sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA== + +d3-random@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-2.2.2.tgz#5eebd209ef4e45a2b362b019c1fb21c2c98cbb6e" + integrity sha512-0D9P8TRj6qDAtHhRQn6EfdOtHMfsUWanl3yb/84C4DqpZ+VsgfI5iTVRNRbELCfNvRfpMr8OrqqUTQ6ANGCijw== + +d3-scale@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-3.3.0.tgz#28c600b29f47e5b9cd2df9749c206727966203f3" + integrity sha512-1JGp44NQCt5d1g+Yy+GeOnZP7xHo0ii8zsQp6PGzd+C1/dl0KGsp9A7Mxwp+1D1o4unbTTxVdU/ZOIEBoeZPbQ== + dependencies: + d3-array "^2.3.0" + d3-format "1 - 2" + d3-interpolate "1.2.0 - 2" + d3-time "^2.1.1" + d3-time-format "2 - 3" + +d3-shape@^1.0.6, d3-shape@^1.2.0: + version "1.3.7" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" + integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw== + dependencies: + d3-path "1" + +d3-shape@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-2.1.0.tgz#3b6a82ccafbc45de55b57fcf956c584ded3b666f" + integrity sha512-PnjUqfM2PpskbSLTJvAzp2Wv4CZsnAgTfcVRTwW03QR3MkXF8Uo7B1y/lWkAsmbKwuecto++4NlsYcvYpXpTHA== + dependencies: + d3-path "1 - 2" + +"d3-time-format@2 - 3": + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6" + integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== + dependencies: + d3-time "1 - 2" + +d3-time-format@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== + dependencies: + d3-time "1 - 3" + +"d3-time@1 - 2", d3-time@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682" + integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ== + dependencies: + d3-array "2" + +"d3-time@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" + integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== + dependencies: + d3-array "2 - 3" + +d3-voronoi@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" + integrity sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg== + dag-map@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-1.0.2.tgz#e8379f041000ed561fc515475c1ed2c85eece8d7" @@ -9051,6 +9758,11 @@ dayjs@^1.8.15: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.7.tgz#4b296922642f70999544d1144a2c25730fce63e2" integrity sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ== +debounce@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -11892,6 +12604,16 @@ internal-slot@^1.0.5: has "^1.0.3" side-channel "^1.0.4" +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== + +internmap@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" + integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== + interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" @@ -13500,6 +14222,11 @@ markdown-to-jsx@^7.1.8: resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.2.0.tgz#e7b46b65955f6a04d48a753acd55874a14bdda4b" integrity sha512-3l4/Bigjm4bEqjCR6Xr+d4DtM1X6vvtGsMGSjJYyep8RjjIvcWtrXBS8Wbfe1/P+atKNMccpsraESIaWVplzVg== +math-expression-evaluator@^1.2.14: + version "1.4.0" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.4.0.tgz#3d66031117fbb7b9715ea6c9c68c2cd2eebd37e2" + integrity sha512-4vRUvPyxdO8cWULGTh9dZWL2tZK6LDBvj+OGHBER7poH9Qdt7kXEoj20wiz4lQUbUXQZFjPbe5mVDo9nutizCw== + md5-file@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-3.2.3.tgz#f9bceb941eca2214a4c0727f5e700314e770f06f" @@ -14069,6 +14796,11 @@ minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" +mitt@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230" + integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg== + mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -15363,7 +16095,7 @@ prompts@^2.3.2, prompts@^2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -15788,6 +16520,13 @@ react-style-singleton@^2.2.1: invariant "^2.2.4" tslib "^2.0.0" +react-use-measure@^2.0.4: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-use-measure/-/react-use-measure-2.1.1.tgz#5824537f4ee01c9469c45d5f7a8446177c6cc4ba" + integrity sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig== + dependencies: + debounce "^1.2.1" + react@18.2.0, react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" @@ -15940,6 +16679,22 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +reduce-css-calc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + integrity sha512-0dVfwYVOlf/LBA2ec4OwQ6p3X9mYxn/wOl2xTcLwjnPYrkgEfPx3VI4eGCH3rQLlPISG5v9I9bkZosKsNRTRKA== + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.3.tgz#60350f7fb252c0a67eb10fd4694d16909971300f" + integrity sha512-Hl/tuV2VDgWgCSEeWMLwxLZqX7OK59eU1guxXsRKTAyeYimivsKdtcV4fu3r710tpG5GmDKDhQ0HSZLExnNmyQ== + dependencies: + balanced-match "^1.0.0" + reforest@^0.12.1: version "0.12.3" resolved "https://registry.yarnpkg.com/reforest/-/reforest-0.12.3.tgz#1c2d9fb5fb2d6870ce077c75eccddb59c3a6bd36"