diff --git a/packages/app/package.json b/packages/app/package.json index 6f9b8c052b..e2f304fee1 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -43,6 +43,7 @@ "http-proxy-middleware": "^2.0.1", "intercept-stdout": "^0.1.2", "konva": "^7.2.5", + "konva-node": "^0.11.2", "lodash": "^4.17.21", "match-sorter": "^6.3.1", "next": "^12.0.4", diff --git a/packages/app/src/components/age-demographic/age-demographic-chart.tsx b/packages/app/src/components/age-demographic/age-demographic-chart.tsx index d5960da447..8dd6c7a8ed 100644 --- a/packages/app/src/components/age-demographic/age-demographic-chart.tsx +++ b/packages/app/src/components/age-demographic/age-demographic-chart.tsx @@ -1,4 +1,4 @@ -import { Color, colors } from '@corona-dashboard/common'; +import { Color, colors, KeysOfType } from '@corona-dashboard/common'; import css from '@styled-system/css'; import { AxisBottom, TickRendererProps } from '@visx/axis'; import { GridColumns } from '@visx/grid'; @@ -32,8 +32,8 @@ interface AgeDemographicChartProps { onMouseMoveBar: (value: T, event: MouseEvent) => void; onMouseLeaveBar: () => void; onKeyInput: (event: KeyboardEvent) => void; - rightMetricProperty: keyof T; - leftMetricProperty: keyof T; + rightMetricProperty: KeysOfType; + leftMetricProperty: KeysOfType; rightColor: Color; leftColor: Color; maxDisplayValue?: number; @@ -88,18 +88,16 @@ export function AgeDemographicChart({ const annotations = useAccessibilityAnnotations(accessibility); - const getNumberValue = (data: T, key: keyof T): number => { - const value = data[key]; - return typeof value === 'number' ? value : 0; - }; - const hasClippedValue = !!values.find( (value) => getIsClipped( - getNumberValue(value, leftMetricProperty), + value[leftMetricProperty] as unknown as number, maxDisplayValue ) || - getIsClipped(getNumberValue(value, rightMetricProperty), maxDisplayValue) + getIsClipped( + value[rightMetricProperty] as unknown as number, + maxDisplayValue + ) ); return ( @@ -193,12 +191,12 @@ export function AgeDemographicChart({ const rightBarWidth = rightPoint(value); const isClippedLeftGroup = getIsClipped( - getNumberValue(value, leftMetricProperty), + value[leftMetricProperty] as unknown as number, maxDisplayValue ); const isClippedRightGroup = getIsClipped( - getNumberValue(value, rightMetricProperty), + value[rightMetricProperty] as unknown as number, maxDisplayValue ); diff --git a/packages/app/src/components/age-demographic/age-demographic-coordinates.ts b/packages/app/src/components/age-demographic/age-demographic-coordinates.ts index c04fb2d9a5..0b780a405a 100644 --- a/packages/app/src/components/age-demographic/age-demographic-coordinates.ts +++ b/packages/app/src/components/age-demographic/age-demographic-coordinates.ts @@ -1,3 +1,4 @@ +import { KeysOfType } from '@corona-dashboard/common'; import { localPoint } from '@visx/event'; import { scaleBand, scaleLinear, ScaleTypeToD3Scale } from '@visx/scale'; import { MouseEvent, useMemo } from 'react'; @@ -41,8 +42,8 @@ export function useAgeDemographicCoordinates< T extends AgeDemographicDefaultValue >( data: { values: T[] }, - rightMetricProperty: keyof T, - leftMetricProperty: keyof T, + rightMetricProperty: KeysOfType, + leftMetricProperty: KeysOfType, maxDisplayValue?: number ) { const [ref, { width = 840 }] = useResizeObserver(); @@ -78,8 +79,8 @@ function calculateAgeDemographicCoordinates< T extends AgeDemographicDefaultValue >( data: { values: T[] }, - rightMetricProperty: keyof T, - leftMetricProperty: keyof T, + rightMetricProperty: KeysOfType, + leftMetricProperty: KeysOfType, isSmallScreen: boolean, parentWidth: number, isExtraSmallScreen: boolean, @@ -117,14 +118,10 @@ function calculateAgeDemographicCoordinates< const yMax = height - margin.top - margin.bottom; // Helper functions to retrieve parts of the values - const getLeftValue = (value: T) => { - const leftValue = value[leftMetricProperty]; - return typeof leftValue === 'number' ? leftValue : 0; - }; - const getRightValue = (value: T) => { - const rightValue = value[rightMetricProperty]; - return typeof rightValue === 'number' ? rightValue : 0; - }; + const getLeftValue = (value: T) => + value[leftMetricProperty] as unknown as number; + const getRightValue = (value: T) => + value[rightMetricProperty] as unknown as number; const ageGroupRange = (value: T) => value.age_group_range; // Scales to map between values and coordinates diff --git a/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx b/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx index 45ba7eea45..42f11af3fe 100644 --- a/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx +++ b/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx @@ -1,4 +1,4 @@ -import type { Color } from '@corona-dashboard/common'; +import type { Color, KeysOfType } from '@corona-dashboard/common'; import css from '@styled-system/css'; import styled from 'styled-components'; import { BoldText } from '~/components/typography'; @@ -11,8 +11,8 @@ interface AgeDemographicTooltipContentProps< T extends AgeDemographicDefaultValue > { value: T; - rightMetricProperty: keyof T; - leftMetricProperty: keyof T; + rightMetricProperty: KeysOfType; + leftMetricProperty: KeysOfType; rightColor: Color; leftColor: Color; text: AgeDemographicChartText; @@ -30,13 +30,6 @@ export function AgeDemographicTooltipContent< text, formatValue, }: AgeDemographicTooltipContentProps) { - const valueRight = value[rightMetricProperty]; - const rightMetricPropertyValue = - typeof valueRight === 'number' ? valueRight : 0; - - const valueLeft = value[leftMetricProperty]; - const leftMetricPropertyValue = typeof valueLeft === 'number' ? valueLeft : 0; - return ( <> @@ -48,13 +41,17 @@ export function AgeDemographicTooltipContent< - {formatValue(rightMetricPropertyValue)}{' '} + + {formatValue(value[rightMetricProperty] as unknown as number)} + {' '} {replaceVariablesInText(text.right_tooltip, { ageGroupRange: formatAgeGroupRange(value.age_group_range), })} - {formatValue(leftMetricPropertyValue)}{' '} + + {formatValue(value[leftMetricProperty] as unknown as number)} + {' '} {replaceVariablesInText(text.left_tooltip, { ageGroupRange: formatAgeGroupRange(value.age_group_range), })} diff --git a/packages/app/src/components/age-demographic/age-demographic.tsx b/packages/app/src/components/age-demographic/age-demographic.tsx index 1df3aec23a..0531ea5654 100644 --- a/packages/app/src/components/age-demographic/age-demographic.tsx +++ b/packages/app/src/components/age-demographic/age-demographic.tsx @@ -1,4 +1,4 @@ -import type { Color } from '@corona-dashboard/common'; +import type { Color, KeysOfType } from '@corona-dashboard/common'; import { Box } from '~/components/base'; import { ErrorBoundary } from '~/components/error-boundary'; import { Tooltip, useTooltip } from '~/components/tooltip'; @@ -16,8 +16,8 @@ import { AgeDemographicChartText, AgeDemographicDefaultValue } from './types'; export interface AgeDemographicProps { data: { values: T[] }; - rightMetricProperty: keyof T; - leftMetricProperty: keyof T; + rightMetricProperty: KeysOfType; + leftMetricProperty: KeysOfType; rightColor: Color; leftColor: Color; /** diff --git a/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx b/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx index 5eaa21ee3c..350fb94d95 100644 --- a/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx +++ b/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx @@ -321,7 +321,7 @@ const Outlines = memo((props: OutlinesProps) => { type FeaturesProps = { geoInfo: ProjectedGeoInfo[]; featureProps: FeatureProps; - children: React.ReactNode; + children: any; }; const Features = memo((props: FeaturesProps) => { diff --git a/packages/app/src/components/choropleth/index.tsx b/packages/app/src/components/choropleth/index.tsx index ae330f6255..398988d5ec 100644 --- a/packages/app/src/components/choropleth/index.tsx +++ b/packages/app/src/components/choropleth/index.tsx @@ -1,3 +1,4 @@ +import { KeysOfType } from '@corona-dashboard/common'; import css from '@styled-system/css'; import type { GeoProjection } from 'd3-geo'; import withLoadingProps from 'next-dynamic-loading-props'; @@ -63,12 +64,16 @@ export type OptionalDataConfig = { /** * A top-level property name of either VR_COLLECTION.json or GM_COLLECTION.json */ - metricName: keyof InferedDataCollection; + metricName: KeysOfType, T[]>; /** * A property name of the object determined by the metric name. This value is used to determine the color * of the feature. */ - metricProperty: keyof T; + metricProperty: KeysOfType< + T, + string | number | null | boolean | undefined, + true + >; /** * The color that is used for the feature when no data is available (a null value for example). */ diff --git a/packages/app/src/components/choropleth/logic/create-data-config.ts b/packages/app/src/components/choropleth/logic/create-data-config.ts index c842339d89..588085d766 100644 --- a/packages/app/src/components/choropleth/logic/create-data-config.ts +++ b/packages/app/src/components/choropleth/logic/create-data-config.ts @@ -18,8 +18,8 @@ export function createDataConfig( ) { if (partialDataConfig.metricName === 'veiligheidsregio') { return { - metricName: 'veiligheidsregio', - metricProperty: 'admissions_on_date_of_admission', + metricName: 'veiligheidsregio' as any, + metricProperty: 'admissions_on_date_of_admission' as any, areaStroke: colors.white, areaStrokeWidth: 1, hoverFill: colors.white, diff --git a/packages/app/src/components/choropleth/logic/types.ts b/packages/app/src/components/choropleth/logic/types.ts index 6e7dae15d7..854f3b5a7c 100644 --- a/packages/app/src/components/choropleth/logic/types.ts +++ b/packages/app/src/components/choropleth/logic/types.ts @@ -1,19 +1,7 @@ import type { GmCollection, - GmCollectionHospitalNice, - GmCollectionSewer, - GmCollectionTestedOverall, - GmCollectionVaccineCoveragePerAgeGroup, + KeysOfType, VrCollection, - VrCollectionBehavior, - VrCollectionDisabilityCare, - VrCollectionElderlyAtHome, - VrCollectionHospitalNice, - VrCollectionNursingHome, - VrCollectionSewer, - VrCollectionSituations, - VrCollectionTestedOverall, - VrCollectionVaccineCoveragePerAgeGroup, } from '@corona-dashboard/common'; import type { ParsedFeature } from '@visx/geo/lib/projections/Projection'; import type { @@ -47,18 +35,9 @@ export enum CHOROPLETH_ASPECT_RATIO { */ export type MapType = 'gm' | 'vr'; -const CODE_PROP_GM = 'gmcode'; -const CODE_PROP_VR = 'vrcode'; -const CODE_PROP_COUNTRY = 'country_code'; - export type CodeProp = - | typeof CODE_PROP_GM - | typeof CODE_PROP_VR - | typeof CODE_PROP_COUNTRY; - -export const isCodeProp = (input: string): input is CodeProp => { - return [CODE_PROP_GM, CODE_PROP_VR, CODE_PROP_COUNTRY].includes(input); -}; + | KeysOfType + | KeysOfType; export const mapToCodeType: Record = { gm: 'gmcode', @@ -80,24 +59,22 @@ export type InferedDataCollection = ? VrCollection : never; -export type VrDataCollection = - | VrCollectionHospitalNice[] - | VrCollectionHospitalNice[] - | VrCollectionTestedOverall[] - | VrCollectionNursingHome[] - | VrCollectionSewer[] - | VrCollectionBehavior[] - | VrCollectionDisabilityCare[] - | VrCollectionElderlyAtHome[] - | VrCollectionSituations[] - | VrCollectionVaccineCoveragePerAgeGroup[]; +/** + * Select all the item types of all the properties from the VrCollection with an array type that has a vrcode property + */ +export type VrDataCollection = VrCollection[KeysOfType< + VrCollection, + { vrcode: string }[] +>]; export type VrDataItem = VrDataCollection[number]; -export type GmDataCollection = - | GmCollectionHospitalNice[] - | GmCollectionTestedOverall[] - | GmCollectionSewer[] - | GmCollectionVaccineCoveragePerAgeGroup[]; +/** + * Select all the item types of all the properties from the GmCollection with an array type that has a gmcode property + */ +export type GmDataCollection = GmCollection[KeysOfType< + GmCollection, + { gmcode: string }[] +>]; export type GmDataItem = GmDataCollection[number]; /** diff --git a/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts b/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts index 05620d2151..9c682c00b5 100644 --- a/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts +++ b/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts @@ -9,13 +9,7 @@ import { useIsTouchDevice } from '~/utils/use-is-touch-device'; import { DataConfig, DataOptions } from '..'; import { TooltipSettings } from '../tooltips/types'; import { thresholds } from './thresholds'; -import { - ChoroplethDataItem, - CodeProp, - isCodeProp, - mapToCodeType, - MapType, -} from './types'; +import { ChoroplethDataItem, mapToCodeType, MapType } from './types'; import { useFeatureName } from './use-feature-name'; import { isCodedValueType } from './utils'; @@ -68,12 +62,9 @@ export function useChoroplethTooltip( const getFeatureName = useFeatureName(map, dataOptions.getFeatureName); const getItemByCode = useMemo(() => { - return (code: CodeProp) => { + return (code: string) => { const item = data - .filter((x) => { - const filterFn = isCodedValueType(codeType); - return filterFn && filterFn(x); - }) + .filter(isCodedValueType(codeType)) .find((x) => (x as any)[codeType] === code); assert( item, @@ -86,9 +77,7 @@ export function useChoroplethTooltip( const threshold = thresholds[map][dataConfig.metricProperty as string]; assert( isDefined(threshold), - `[${ - useChoroplethTooltip.name - }] No threshold configured for map type ${map} and metric property ${dataConfig.metricProperty.toString()}` + `[${useChoroplethTooltip.name}] No threshold configured for map type ${map} and metric property ${dataConfig.metricProperty.toString()}` ); useEffect(() => { @@ -102,7 +91,7 @@ export function useChoroplethTooltip( return; } - function handleBubbledFocusIn(event: FocusEvent): void { + function handleBubbledFocusIn(event: FocusEvent): any { const link = event.target as HTMLAnchorElement; if (!isDefined(link)) { return; @@ -110,7 +99,7 @@ export function useChoroplethTooltip( const code = link.getAttribute('data-id'); - if (isPresent(code) && isPresent(container) && isCodeProp(code)) { + if (isPresent(code) && isPresent(container)) { const bboxContainer = container.getBoundingClientRect(); const bboxLink = link.getBoundingClientRect(); const left = bboxLink.left - bboxContainer.left; @@ -194,7 +183,7 @@ type HoverInfo = { code: string; x: number; y: number }; const createTooltipTrigger = ( setTooltip: (settings: TooltipSettings | undefined) => void, - getItemByCode: (code: CodeProp) => T, + getItemByCode: (code: string) => T, dataConfig: DataConfig, dataOptions: DataOptions, threshold: ChoroplethThresholdsValue[], @@ -203,7 +192,7 @@ const createTooltipTrigger = ( metricPropertyFormatter: (value: number) => string ) => { return (hoverInfo?: HoverInfo) => { - if (!isDefined(hoverInfo) || !isCodeProp(hoverInfo.code)) { + if (!isDefined(hoverInfo)) { return setTooltip(undefined); } @@ -229,7 +218,7 @@ const createFeatureMouseOverHandler = ( timeout: MutableRefObject, setTooltip: (settings: TooltipSettings | undefined) => void, ref: RefObject, - getItemByCode: (code: CodeProp) => T, + getItemByCode: (code: string) => T, dataConfig: DataConfig, dataOptions: DataOptions, threshold: ChoroplethThresholdsValue[], @@ -241,7 +230,7 @@ const createFeatureMouseOverHandler = ( const elm = event.target as HTMLElement; const code = elm.getAttribute('data-id'); - if (isPresent(code) && isCodeProp(code) && ref.current) { + if (isPresent(code) && ref.current) { if (timeout.current > -1) { clearTimeout(timeout.current); timeout.current = -1; @@ -292,10 +281,9 @@ function useMetricPropertyFormatter( intl: IntlContextProps ) { return useMemo(() => { - const values = data.map((value) => { - const valueEntry = value[dataConfig.metricProperty]; - return typeof valueEntry === 'number' ? valueEntry : 0; - }); + const values = data.map( + (x) => x[dataConfig.metricProperty] as unknown as number + ); const numberOfDecimals = getMaximumNumberOfDecimals(values); return (value: number) => intl.formatPercentage(value, { diff --git a/packages/app/src/components/choropleth/logic/use-fill-color.ts b/packages/app/src/components/choropleth/logic/use-fill-color.ts index 68088f29c0..9c9a164b39 100644 --- a/packages/app/src/components/choropleth/logic/use-fill-color.ts +++ b/packages/app/src/components/choropleth/logic/use-fill-color.ts @@ -34,9 +34,7 @@ export function useFillColor( const threshold = thresholds[thresholdMap || map][metricProperty as string]; assert( isDefined(threshold), - `[${ - useFillColor.name - }] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` + `[${useFillColor.name}] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` ); const colorScale = useMemo(() => createColorScale(threshold), [threshold]); @@ -60,9 +58,7 @@ export function getFillColor( const threshold = thresholds[thresholdMap || map][metricProperty as string]; assert( isDefined(threshold), - `[${ - getFillColor.name - }] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` + `[${getFillColor.name}] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` ); const colorScale = createColorScale(threshold); @@ -98,10 +94,7 @@ function createGetValueByCode( ) { return (code: string) => { const item = data - .filter((x) => { - const filterFn = isCodedValueType(codeType); - return filterFn && filterFn(x); - }) + .filter(isCodedValueType(codeType)) .find((x) => (x as unknown as Record)[codeType] === code); return isDefined(item) && isPresent(item[metricProperty]) diff --git a/packages/app/src/components/choropleth/logic/utils.ts b/packages/app/src/components/choropleth/logic/utils.ts index 1d6d0414a4..4c81a00f31 100644 --- a/packages/app/src/components/choropleth/logic/utils.ts +++ b/packages/app/src/components/choropleth/logic/utils.ts @@ -2,6 +2,7 @@ import type { ParsedFeature } from '@visx/geo/lib/projections/Projection'; import type { Feature, MultiPolygon, Polygon } from 'geojson'; import { isPresent } from 'ts-is-present'; import type { + ChoroplethDataItem, CodedGeoProperties, CodeProp, GmDataItem, @@ -18,11 +19,11 @@ export function isCodedValueType(codeType: CodeProp) { } } -export function isGmData(item: any): item is GmDataItem { +export function isGmData(item: ChoroplethDataItem): item is GmDataItem { return 'gmcode' in item; } -export function isVrData(item: any): item is VrDataItem { +export function isVrData(item: ChoroplethDataItem): item is VrDataItem { return 'vrcode' in item; } diff --git a/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx b/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx index c2281a4448..037fc3f93e 100644 --- a/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx +++ b/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx @@ -36,11 +36,7 @@ export function ChoroplethTooltip( )[data.map]?.[data.dataConfig.metricProperty as string]?.subject; assert( isDefined(subject), - `[${ - ChoroplethTooltip.name - }] No tooltip subject found in siteText.choropleth_tooltip.${ - data.map - }.${data.dataConfig.metricProperty.toString()}` + `[${ChoroplethTooltip.name}] No tooltip subject found in siteText.choropleth_tooltip.${data.map}.${data.dataConfig.metricProperty.toString()}` ); const tooltipContent = ( @@ -48,11 +44,7 @@ export function ChoroplethTooltip( )[data.map]?.[data.dataConfig.metricProperty as string]?.content; assert( isDefined(tooltipContent), - `[${ - ChoroplethTooltip.name - }] No tooltip content found in siteText.choropleth_tooltip.${ - data.map - }.${data.dataConfig.metricProperty.toString()}` + `[${ChoroplethTooltip.name}] No tooltip content found in siteText.choropleth_tooltip.${data.map}.${data.dataConfig.metricProperty.toString()}` ); const tooltipVars = { @@ -82,8 +74,6 @@ export function ChoroplethTooltip( // This line is to make sure the content is readible by screenreaders and does not skip numbers after a new line const ariaContent = content.replace(/(\n|\*)/g, ''); - const dataItem = data.dataItem[data.dataConfig.metricProperty]; - const filterBelow = typeof dataItem === 'number' ? dataItem : null; return ( ( {ariaContent} diff --git a/packages/app/src/components/cms/inline-age-demographic.tsx b/packages/app/src/components/cms/inline-age-demographic.tsx index bc0bc16bc1..391dd2ea39 100644 --- a/packages/app/src/components/cms/inline-age-demographic.tsx +++ b/packages/app/src/components/cms/inline-age-demographic.tsx @@ -8,7 +8,6 @@ import { get } from 'lodash'; import useSWRImmutable from 'swr/immutable'; import { isDefined } from 'ts-is-present'; import { useIntl } from '~/intl'; -import { AccessibilityDefinition } from '~/utils/use-accessibility-annotations'; import { AgeDemographic } from '../age-demographic'; import { ErrorBoundary } from '../error-boundary'; import { Metadata } from '../metadata'; @@ -19,8 +18,7 @@ import { getDataUrl } from './logic/get-data-url'; interface InlineAgeDemographicProps { configuration: AgeDemographicConfiguration< DataScopeKey, - MetricKeys, - AccessibilityDefinition['key'] + MetricKeys >; startDate?: string; endDate?: string; @@ -47,11 +45,11 @@ export function InlineAgeDemographic(props: InlineAgeDemographicProps) { return ( `${n}`} diff --git a/packages/app/src/components/cms/inline-choropleth.tsx b/packages/app/src/components/cms/inline-choropleth.tsx index d1cbd8b435..6016cf616f 100644 --- a/packages/app/src/components/cms/inline-choropleth.tsx +++ b/packages/app/src/components/cms/inline-choropleth.tsx @@ -15,7 +15,7 @@ import { DynamicChoropleth, OptionalDataConfig, } from '../choropleth'; -import { ChoroplethDataItem, InferedDataCollection } from '../choropleth/logic'; +import { ChoroplethDataItem } from '../choropleth/logic'; import { ErrorBoundary } from '../error-boundary'; import { Metadata } from '../metadata'; import { InlineLoader } from './inline-loader'; @@ -58,9 +58,8 @@ export function InlineChoropleth(props: InlineChoroplethProps) { }; const dataConfig: OptionalDataConfig = { - metricName: - configuration.metricName as keyof InferedDataCollection, - metricProperty: configuration.metricProperty as keyof ChoroplethDataItem, + metricName: configuration.metricName as any, + metricProperty: configuration.metricProperty as any, areaStroke: getColor(configuration.areaStroke), areaStrokeWidth: configuration.areaStrokeWidth, highlightStroke: getColor(configuration.highlightStroke), diff --git a/packages/app/src/components/cms/rich-content.tsx b/packages/app/src/components/cms/rich-content.tsx index ddf11f0ee8..938e22590f 100644 --- a/packages/app/src/components/cms/rich-content.tsx +++ b/packages/app/src/components/cms/rich-content.tsx @@ -30,7 +30,6 @@ import { import { assert } from '~/utils/assert'; import { isAbsoluteUrl } from '~/utils/is-absolute-url'; import { Link } from '~/utils/link'; -import { AccessibilityDefinition } from '~/utils/use-accessibility-annotations'; import { Heading } from '../typography'; import { ContentImage } from './content-image'; import { InlineAgeDemographic } from './inline-age-demographic'; @@ -56,7 +55,7 @@ interface AgeDemographicConfigNode { title: string; startDate?: string; endDate?: string; - config: AgeDemographicConfiguration, AccessibilityDefinition['key']>; + config: AgeDemographicConfiguration>; } interface ChoroplethConfigNode { diff --git a/packages/app/src/components/pie-chart.tsx b/packages/app/src/components/pie-chart.tsx index 78bc9ad48c..3b10099fd3 100644 --- a/packages/app/src/components/pie-chart.tsx +++ b/packages/app/src/components/pie-chart.tsx @@ -1,3 +1,4 @@ +import type { KeysOfType } from '@corona-dashboard/common'; import { Chevron } from '@corona-dashboard/icons'; import css from '@styled-system/css'; import { Group } from '@visx/group'; @@ -15,7 +16,7 @@ import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; const ICON_SIZE = 55; export interface PiePartConfig { - metricProperty: keyof T; + metricProperty: KeysOfType; color: string; label: string; tooltipLabel: string; @@ -71,13 +72,11 @@ export function PieChart({ formatDateSpan, }; - const totalValue = dataConfig.reduce((previousValue, currentValue) => { - const metricPropertyValue = data[currentValue.metricProperty]; - return ( - previousValue + - (typeof metricPropertyValue === 'number' ? metricPropertyValue : 0) - ); - }, 0); + const totalValue = dataConfig.reduce( + (previousValue, currentValue) => + previousValue + (data[currentValue.metricProperty] as unknown as number), + 0 + ); const mappedDataWithValues = useMemo( () => @@ -86,7 +85,7 @@ export function PieChart({ return { __value: Math.max( - typeof currentProperty === 'number' ? currentProperty : 0, + currentProperty as unknown as number, totalValue * (minimumPercentage / 100) * 2 ), ...config, diff --git a/packages/app/src/components/spark-line.tsx b/packages/app/src/components/spark-line.tsx index 4f64084955..36d1af5009 100644 --- a/packages/app/src/components/spark-line.tsx +++ b/packages/app/src/components/spark-line.tsx @@ -1,7 +1,8 @@ -import type { TimestampedValue } from '@corona-dashboard/common'; +import type { KeysOfType, TimestampedValue } from '@corona-dashboard/common'; import { colors } from '@corona-dashboard/common'; import { scaleLinear } from '@visx/scale'; import { AreaClosed, LinePath } from '@visx/shape'; +import { NumberValue } from 'd3-scale'; import { first, last } from 'lodash'; import { isPresent } from 'ts-is-present'; @@ -10,7 +11,7 @@ const HEIGHT = 24; const MARKER_RADIUS = 2.5; type SparkLineProps = { - averageProperty: keyof T; + averageProperty: KeysOfType; data: T[]; }; @@ -30,20 +31,14 @@ export function SparkLine( props: SparkLineProps ) { const { data, averageProperty } = props; - - const getNumberValue = (data: T, key: keyof T): number => { - const value = data[key]; - return typeof value === 'number' ? value : 0; - }; - const numberOfPoints = data.length; const min = Math.min( 0, - ...data.map((d) => getNumberValue(d, averageProperty)) + ...data.map((d) => (d[averageProperty] as unknown as number) ?? 0) ); const max = Math.max( 0.1, - ...data.map((d) => getNumberValue(d, averageProperty)) + ...data.map((d) => (d[averageProperty] as unknown as number) ?? 0) ); const xScale = scaleLinear({ domain: [getDate(first(data)), getDate(last(data))], @@ -60,7 +55,7 @@ export function SparkLine( } function getY(dataPoint: T) { - return yScale(getNumberValue(dataPoint, averageProperty)); + return yScale(dataPoint[averageProperty] as unknown as NumberValue); } const nonNullValues = data.filter((x) => isPresent(x[averageProperty])); diff --git a/packages/app/src/components/time-series-chart/components/axes.tsx b/packages/app/src/components/time-series-chart/components/axes.tsx index ac115f1792..dc42a92bd3 100644 --- a/packages/app/src/components/time-series-chart/components/axes.tsx +++ b/packages/app/src/components/time-series-chart/components/axes.tsx @@ -13,7 +13,7 @@ import { DateSpanValue, } from '@corona-dashboard/common'; import css from '@styled-system/css'; -import { AxisBottom, AxisLeft, TickFormatter } from '@visx/axis'; +import { AxisBottom, AxisLeft } from '@visx/axis'; import { GridRows } from '@visx/grid'; import { scaleLinear } from '@visx/scale'; import { NumberValue, ScaleBand, ScaleLinear } from 'd3-scale'; @@ -49,7 +49,7 @@ export type AxesProps = { timeDomain: [number, number]; xTickNumber?: number; values?: T[]; - formatYTickValue?: TickFormatter; + formatYTickValue?: (value: number) => string; /** * On narrow screens we'll "collapse" the Y-axis. Only the low value will be @@ -92,6 +92,8 @@ function createTimeTicks(startTick: number, endTick: number, count: number) { return ticks; } +export type AnyTickFormatter = (value: any) => string; + export const Axes = memo(function Axes({ numGridLines, showWeekNumbers, @@ -127,13 +129,13 @@ export const Axes = memo(function Axes({ const { formatDateFromSeconds, formatNumber, formatPercentage } = useIntl(); - const formatYAxis: TickFormatter = useCallback( - (y: NumberValue) => formatNumber(y as number), + const formatYAxis = useCallback( + (y: number) => formatNumber(y), [formatNumber] ); - const formatYAxisPercentage: TickFormatter = useCallback( - (y: NumberValue) => `${formatPercentage(y as number)}%`, + const formatYAxisPercentage = useCallback( + (y: number) => `${formatPercentage(y)}%`, [formatPercentage] ); @@ -354,10 +356,10 @@ export const Axes = memo(function Axes({ stroke={colors.silver} tickFormat={ formatYTickValue - ? formatYTickValue + ? (formatYTickValue as AnyTickFormatter) : isPercentage - ? formatYAxisPercentage - : formatYAxis + ? (formatYAxisPercentage as AnyTickFormatter) + : (formatYAxis as AnyTickFormatter) } tickLabelProps={() => ({ fill: colors.data.axisLabels, @@ -386,10 +388,10 @@ export const Axes = memo(function Axes({ stroke={colors.silver} tickFormat={ formatYTickValue - ? formatYTickValue + ? (formatYTickValue as AnyTickFormatter) : isPercentage - ? formatYAxisPercentage - : formatYAxis + ? (formatYAxisPercentage as AnyTickFormatter) + : (formatYAxis as AnyTickFormatter) } tickLabelProps={() => ({ fill: colors.data.axisLabels, diff --git a/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx b/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx index 606dbd8f75..633697e751 100644 --- a/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx +++ b/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx @@ -37,7 +37,7 @@ export function TooltipSeriesListItems({ return ( - {seriesConfig.map((serie, index) => { + {seriesConfig.map((x, index) => { /** * The key is unique for every date to make sure a screenreader * will read `[label]: [value]`. Otherwise it would read the @@ -45,27 +45,23 @@ export function TooltipSeriesListItems({ * context. */ const key = index + getDateUnixString(value); - const metricProperty = serie.type !== 'range' && serie.metricProperty; - const metricPropertyValue = metricProperty - ? value[metricProperty] - : null; + const metricPropertyValue = + x.type !== 'range' && + (value[x.metricProperty] as unknown as number | null); - const tooltipValue = - typeof metricPropertyValue === 'number' ? metricPropertyValue : null; - - switch (serie.type) { + switch (x.type) { case 'range': return ( } - label={serie.shortLabel ?? serie.label} - ariaLabel={serie.ariaLabel} + icon={} + label={x.shortLabel ?? x.label} + ariaLabel={x.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={serie.nonInteractive} + isVisuallyHidden={x.nonInteractive} > - {formatSeriesValue(value, serie, options.isPercentage)} + {formatSeriesValue(value, x, options.isPercentage)} ); @@ -74,15 +70,15 @@ export function TooltipSeriesListItems({ return ( {formatSeriesValue( value, - serie, - serie.isPercentage ?? options.isPercentage + x, + x.isPercentage ?? options.isPercentage )} ); @@ -92,13 +88,18 @@ export function TooltipSeriesListItems({ return ( } - label={serie.shortLabel ?? serie.label} - ariaLabel={serie.ariaLabel} + icon={ + + } + label={x.shortLabel ?? x.label} + ariaLabel={x.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={serie.nonInteractive} + isVisuallyHidden={x.nonInteractive} > - {formatSeriesValue(value, serie, options.isPercentage)} + {formatSeriesValue(value, x, options.isPercentage)} ); @@ -107,20 +108,20 @@ export function TooltipSeriesListItems({ ) : ( - + ) } - label={serie.shortLabel ?? serie.label} - ariaLabel={serie.ariaLabel} + label={x.shortLabel ?? x.label} + ariaLabel={x.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={serie.nonInteractive} + isVisuallyHidden={x.nonInteractive} > - {formatSeriesValue(value, serie, options.isPercentage)} + {formatSeriesValue(value, x, options.isPercentage)} ); } diff --git a/packages/app/src/components/time-series-chart/components/week-numbers.tsx b/packages/app/src/components/time-series-chart/components/week-numbers.tsx index 7ee582b5d2..d8824a748b 100644 --- a/packages/app/src/components/time-series-chart/components/week-numbers.tsx +++ b/packages/app/src/components/time-series-chart/components/week-numbers.tsx @@ -4,10 +4,10 @@ import { WEEK_IN_SECONDS, } from '@corona-dashboard/common'; import css from '@styled-system/css'; -import { AxisTop, TickFormatter } from '@visx/axis'; +import { AxisTop } from '@visx/axis'; import { RectClipPath } from '@visx/clip-path'; import { GridColumns } from '@visx/grid'; -import { NumberValue, ScaleBand, ScaleLinear } from 'd3-scale'; +import { ScaleBand, ScaleLinear } from 'd3-scale'; import { useCallback, useMemo } from 'react'; import { isDefined } from 'ts-is-present'; import { useIntl } from '~/intl'; @@ -15,6 +15,7 @@ import { createDateFromUnixTimestamp } from '~/utils/create-date-from-unix-times import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; import { useUniqueId } from '~/utils/use-unique-id'; import { Bounds, getWeekInfo } from '../logic'; +import { AnyTickFormatter } from './axes'; /** * Only show this amount of week numbers @@ -71,7 +72,7 @@ export function WeekNumbers({ }); }, [commonTexts.common] - ) as TickFormatter; + ); return ( <> @@ -100,7 +101,7 @@ export function WeekNumbers({ ({ diff --git a/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts b/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts index f0b0208ff3..6ba50a12f2 100644 --- a/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts +++ b/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts @@ -18,11 +18,10 @@ export function useFormatSeriesValue( ) { const formatter = metricPropertyFormatters[metricProperty] || intl.formatNumber; - const numberValue = value[metricProperty]; - const formattedValue = - isPresent(numberValue) && typeof numberValue === 'number' - ? formatter(numberValue) - : String(numberValue); + const numberValue = value[metricProperty] as unknown as number | null; + const formattedValue = isPresent(numberValue) + ? formatter(numberValue) + : numberValue; return isPresent(formattedValue) ? isPercentage diff --git a/packages/app/src/components/time-series-chart/time-series-chart.tsx b/packages/app/src/components/time-series-chart/time-series-chart.tsx index faa67e2025..220d9afacc 100644 --- a/packages/app/src/components/time-series-chart/time-series-chart.tsx +++ b/packages/app/src/components/time-series-chart/time-series-chart.tsx @@ -1,8 +1,6 @@ import { TimeframeOption, TimestampedValue } from '@corona-dashboard/common'; import css from '@styled-system/css'; -import { TickFormatter } from '@visx/axis'; import { useTooltip } from '@visx/tooltip'; -import { NumberValue } from 'd3-scale'; import { first, isFunction, last } from 'lodash'; import { useCallback, useEffect, useMemo } from 'react'; import { isDefined } from 'ts-is-present'; @@ -122,7 +120,7 @@ export type TimeSeriesChartProps< showWeekNumbers?: boolean; tickValues?: number[]; xTickNumber?: number; - formatTickValue?: TickFormatter; + formatTickValue?: (value: number) => string; paddingLeft?: number; /** * The data specific options are grouped together. This way we can pass them diff --git a/packages/app/src/components/tooltip.tsx b/packages/app/src/components/tooltip.tsx index 71abee4bcf..6e6bbe96d5 100644 --- a/packages/app/src/components/tooltip.tsx +++ b/packages/app/src/components/tooltip.tsx @@ -1,7 +1,6 @@ import css from '@styled-system/css'; import { MouseEvent, - KeyboardEvent, ReactNode, useCallback, useEffect, @@ -17,7 +16,7 @@ export interface TooltipCoordinates { export type GetTooltipCoordinates = ( value: T, - event?: MouseEvent + event?: MouseEvent ) => TooltipCoordinates; interface TooltipProps { @@ -77,7 +76,7 @@ export function useTooltip({ } const openTooltip = useCallback( - (value: T, event: MouseEvent) => { + (value: T, event: MouseEvent) => { debounceMouseEvents(() => { setCoordinates(getTooltipCoordinates(value, event)); setIsVisible(true); @@ -94,7 +93,7 @@ export function useTooltip({ }, []); const keyboardNavigateTooltip = useCallback( - (event: KeyboardEvent) => { + (event: any) => { if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') { return; } diff --git a/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx b/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx index 327dbc53e8..c083eb4322 100644 --- a/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx +++ b/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx @@ -1,5 +1,6 @@ import { colors, + KeysOfType, VrCollectionBehavior, } from '@corona-dashboard/common'; import css from '@styled-system/css'; @@ -118,7 +119,7 @@ function ChoroplethBlock({ const breakpoints = useBreakpoints(); const isSmallScreen = breakpoints.sm; - const metricProperty = `${currentId}_${behaviorType}` as keyof VrCollectionBehavior; + const metricProperty = `${currentId}_${behaviorType}` as const; return ( @@ -152,7 +153,11 @@ function ChoroplethBlock({ data={data.behavior} dataConfig={{ metricName: 'behavior', - metricProperty, + metricProperty: metricProperty as unknown as KeysOfType< + VrCollectionBehavior, + number | null | boolean | undefined, + true + >, noDataFillColor: colors.offWhite, }} dataOptions={{ diff --git a/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx b/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx index 945dc7a915..e2a1222420 100644 --- a/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx +++ b/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx @@ -10,7 +10,7 @@ import { Box } from '~/components/base'; import { ChartTile } from '~/components/chart-tile'; import { InlineTooltip } from '~/components/inline-tooltip'; import { MetadataProps } from '~/components/metadata'; -import { SeriesConfig, TimeSeriesChart } from '~/components/time-series-chart'; +import { TimeSeriesChart } from '~/components/time-series-chart'; import { TimelineEventConfig } from '~/components/time-series-chart/components/timeline'; import { BoldText } from '~/components/typography'; import { SiteText } from '~/locale'; @@ -20,12 +20,8 @@ import { BehaviorIdentifier, behaviorIdentifiers, } from './logic/behavior-types'; - -type ValueType = NlBehaviorValue | VrBehaviorValue; -type ValueKey = keyof ValueType; - interface BehaviorLineChartTileProps { - values: ValueType[]; + values: NlBehaviorValue[] | VrBehaviorValue[]; metadata: MetadataProps; currentId: BehaviorIdentifier; setCurrentId: React.Dispatch>; @@ -46,15 +42,15 @@ export function BehaviorLineChartTile({ text, }: BehaviorLineChartTileProps) { const selectedComplianceValueKey = - `${currentId}_compliance` as ValueKey; + `${currentId}_compliance` as keyof NlBehaviorValue; const selectedSupportValueKey = - `${currentId}_support` as ValueKey; + `${currentId}_support` as keyof NlBehaviorValue; - const complianceValuesHasGap = useDataHasGaps( + const complianceValuesHasGap = useDataHasGaps( values, selectedComplianceValueKey ); - const supportValuesHasGap = useDataHasGaps(values, selectedSupportValueKey); + const supportValuesHasGap = useDataHasGaps(values, selectedSupportValueKey); const breakpoints = useBreakpoints(); @@ -92,7 +88,7 @@ export function BehaviorLineChartTile({ )} - > + = { label: string; data: T[]; - dataProperty: keyof Unpack; + dataProperty: KeysOfType, number | null, true>; value: number | string; valueIsPercentage?: boolean; warning?: string; diff --git a/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts b/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts index 446d91f1e7..008405785d 100644 --- a/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts +++ b/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts @@ -66,10 +66,9 @@ function getVaccineCoveragePercentageFormatter( } } - const dataEntry = data[property]; - if (isPresent(dataEntry) && typeof dataEntry === 'number') { + if (isPresent(data[property]) && typeof data[property] === 'number') { return ( - formatPercentage(dataEntry, { + formatPercentage(data[property] as unknown as number, { minimumFractionDigits: numFractionDigits, maximumFractionDigits: numFractionDigits, }) + '%' diff --git a/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx b/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx index ed565718d7..7d8648dfd1 100644 --- a/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx +++ b/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx @@ -2,6 +2,7 @@ import { assert, colors, GmCollectionVaccineCoveragePerAgeGroup, + KeysOfType, VrCollectionVaccineCoveragePerAgeGroup, } from '@corona-dashboard/common'; import css from '@styled-system/css'; @@ -243,7 +244,10 @@ export function ChoroplethTooltip( ...data.dataOptions.tooltipVariables, } as Record; - const dataItemKey = data.dataConfig.metricProperty as keyof VaccineCoverageData; + const dataItemKey = data.dataConfig.metricProperty as KeysOfType< + VaccineCoverageData, + number + >; const filterBelow = (dataItemKey === undefined ? null : data.dataItem[dataItemKey]) || null; @@ -296,7 +300,7 @@ export function ChoroplethTooltip( ) => { {isPresent(content.articles) && ( )} diff --git a/packages/app/src/pages/veiligheidsregio/index.tsx b/packages/app/src/pages/veiligheidsregio/index.tsx index 68336298c3..0592b86bfc 100644 --- a/packages/app/src/pages/veiligheidsregio/index.tsx +++ b/packages/app/src/pages/veiligheidsregio/index.tsx @@ -39,18 +39,15 @@ const VrIndexPage = (props: StaticProps) => { }; const code = router.query.code as string; - const data = useMemo( - () => - vrData.map((x) => ({ - date_unix: 0, - admissions_on_date_of_admission: 0, - admissions_on_date_of_admission_per_100000: 0, - admissions_on_date_of_reporting: 0, - date_of_insertion_unix: 0, - vrcode: x.code, - })), - [] - ); + const data = useMemo(() => { + return vrData.map( + (x) => + ({ + vrcode: x.code, + admissions_on_date_of_reporting: null, + } as unknown as VrCollectionHospitalNice) + ); + }, []); return ( diff --git a/packages/app/src/utils/api/strip-trailing-null-values.ts b/packages/app/src/utils/api/strip-trailing-null-values.ts index 43ea0decb0..34b4e7369c 100644 --- a/packages/app/src/utils/api/strip-trailing-null-values.ts +++ b/packages/app/src/utils/api/strip-trailing-null-values.ts @@ -15,7 +15,7 @@ export function stripTrailingNullValues( ) { if ( !metricsInaccurateItems.includes(metric) || - !strippableMetricProperties.includes(metricProperty ?? '') + !strippableMetricProperties.includes(metricProperty as unknown as string) ) { return data; } diff --git a/packages/common/src/types/choropleth.ts b/packages/common/src/types/choropleth.ts index 46dc057237..d8a1ef71d4 100644 --- a/packages/common/src/types/choropleth.ts +++ b/packages/common/src/types/choropleth.ts @@ -8,6 +8,59 @@ import type { VrDifference, } from './data'; +/** + * This type was taken from this Stack Overflow post: https://stackoverflow.com/questions/46583883/typescript-pick-properties-with-a-defined-type + * + * Returns an interface stripped of all keys that don't resolve to U, defaulting + * to a non-strict comparison of T[key] extends U. Setting B to true performs + * a strict type comparison of T[key] extends U & U extends T[key] + * + * Example, if one needs just the keys of type string: + * + * type SomeType = { + * key1: string; + * key2: string; + * key3: number; + * } + * + * const stringKeys = KeysOfType + * + * (stringKeys = key1 | key2) + * + * @TODO Since TypeScript v4.5.5 this util is no longer working as expected. + * Refactoring is needed before a couple of typecasts (as unknown as number) can be removed. + */ +export type KeysOfType = { + [P in keyof T]: B extends true + ? T[P] extends U + ? U extends T[P] + ? P + : never + : never + : T[P] extends U + ? P + : never; +}[keyof T]; + +/** + * This returns a filtered type that only contains the keys of the specified type. + * + * type SomeType = { + * key1: string; + * key2: string; + * key3: number; + * } + * + * const TypeWithJustStringKeys = PickByType + * + * (TypeWithJustStringKeys = { + * key1: string; + * key2: string; + * }) + * + */ +export type PickByType = Pick>; + export type Metric = { values: T[]; last_value: T; diff --git a/packages/common/src/types/inline-charts.ts b/packages/common/src/types/inline-charts.ts index 706c0893c4..192d79c072 100644 --- a/packages/common/src/types/inline-charts.ts +++ b/packages/common/src/types/inline-charts.ts @@ -82,10 +82,9 @@ export type DonutMetricPropertyConfig< export type AgeDemographicConfiguration< S extends DataScopeKey, - M extends MetricKeys, - K extends string + M extends MetricKeys > = { - accessibilityKey: K; + accessibilityKey: string; sourceKey: string; text: string; leftMetricProperty: MetricProperty>; diff --git a/yarn.lock b/yarn.lock index 394be9eb4e..254b688592 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2630,6 +2630,7 @@ __metadata: jsdom: ^18.1.1 jsdom-global: ^3.0.2 konva: ^7.2.5 + konva-node: ^0.11.2 lint-staged: ^11.2.6 lodash: ^4.17.21 lodash-webpack-plugin: ^0.11.6 @@ -3310,6 +3311,25 @@ __metadata: languageName: node linkType: hard +"@mapbox/node-pre-gyp@npm:^1.0.0": + version: 1.0.5 + resolution: "@mapbox/node-pre-gyp@npm:1.0.5" + dependencies: + detect-libc: ^1.0.3 + https-proxy-agent: ^5.0.0 + make-dir: ^3.1.0 + node-fetch: ^2.6.1 + nopt: ^5.0.0 + npmlog: ^4.1.2 + rimraf: ^3.0.2 + semver: ^7.3.4 + tar: ^6.1.0 + bin: + node-pre-gyp: bin/node-pre-gyp + checksum: c1f182a707f5782e47b77a76e9d6a073fb043999cf9ad965bc86732e88db27ad00926d1602918edb7105f05cde67871b84a178ee9844eb742319ade419636675 + languageName: node + linkType: hard + "@mdx-js/react@npm:^1.0.0": version: 1.6.22 resolution: "@mdx-js/react@npm:1.6.22" @@ -7403,15 +7423,6 @@ __metadata: languageName: node linkType: hard -"@types/react-reconciler@npm:~0.26.2": - version: 0.26.7 - resolution: "@types/react-reconciler@npm:0.26.7" - dependencies: - "@types/react": "*" - checksum: 4122d2b08580f775d0aeae9bd10b68248f894096ed14c0ebbc143ef712e21b159e89d0c628bd95dd3329947fc1ee94a0cb1d2d32b32b1d5d225e70030e91e58f - languageName: node - linkType: hard - "@types/react-test-renderer@npm:>=16.9.0, @types/react-test-renderer@npm:^17.0.1": version: 17.0.1 resolution: "@types/react-test-renderer@npm:17.0.1" @@ -10626,6 +10637,18 @@ __metadata: languageName: node linkType: hard +"canvas@npm:^2.5.0": + version: 2.8.0 + resolution: "canvas@npm:2.8.0" + dependencies: + "@mapbox/node-pre-gyp": ^1.0.0 + nan: ^2.14.0 + node-gyp: latest + simple-get: ^3.0.3 + checksum: 4cc909f63eaf88d22f9164601903745abcc6ccb7f70090b9389dc2cb68cbf139c220dbd75837e6d04602ff122b44a2eb17413bca850f9c6c602f74f1f0f1cc3f + languageName: node + linkType: hard + "capital-case@npm:^1.0.4": version: 1.0.4 resolution: "capital-case@npm:1.0.4" @@ -12464,6 +12487,15 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^4.2.0": + version: 4.2.1 + resolution: "decompress-response@npm:4.2.1" + dependencies: + mimic-response: ^2.0.0 + checksum: 4e783ca4dfe9417354d61349750fe05236f565a4415a6ca20983a311be2371debaedd9104c0b0e7b36e5f167aeaae04f84f1a0b3f8be4162f1d7d15598b8fdba + languageName: node + linkType: hard + "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -12695,6 +12727,15 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^1.0.3": + version: 1.0.3 + resolution: "detect-libc@npm:1.0.3" + bin: + detect-libc: ./bin/detect-libc.js + checksum: daaaed925ffa7889bd91d56e9624e6c8033911bb60f3a50a74a87500680652969dbaab9526d1e200a4c94acf80fc862a22131841145a0a8482d60a99c24f4a3e + languageName: node + linkType: hard + "detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.1": version: 2.0.1 resolution: "detect-libc@npm:2.0.1" @@ -17607,7 +17648,17 @@ __metadata: languageName: node linkType: hard -"konva@npm:^7.2.5": +"konva-node@npm:^0.11.2": + version: 0.11.2 + resolution: "konva-node@npm:0.11.2" + dependencies: + canvas: ^2.5.0 + konva: ^7 + checksum: 11d99492c653d6e52c370af5831a4dce60b6cabbf81016806fa58c8563174272db39940b8d638fc29f83f949cf5934471ed7c1d3d1d6c3bad60152450f308fd2 + languageName: node + linkType: hard + +"konva@npm:^7, konva@npm:^7.2.5": version: 7.2.5 resolution: "konva@npm:7.2.5" checksum: 795ab73af38307243f867be3dab122ec6a5c37bc7f44a20359baf2bf6e1d5cd8a9ce9d7e3b69b21dd6429615b8f96254858e346e8ccb4b5fff8be6c5b60cd12d @@ -18734,6 +18785,13 @@ __metadata: languageName: node linkType: hard +"mimic-response@npm:^2.0.0": + version: 2.1.0 + resolution: "mimic-response@npm:2.1.0" + checksum: 014fad6ab936657e5f2f48bd87af62a8e928ebe84472aaf9e14fec4fcb31257a5edff77324d8ac13ddc6685ba5135cf16e381efac324e5f174fb4ddbf902bf07 + languageName: node + linkType: hard + "mimic-response@npm:^3.1.0": version: 3.1.0 resolution: "mimic-response@npm:3.1.0" @@ -18976,7 +19034,7 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.12.1": +"nan@npm:^2.12.1, nan@npm:^2.14.0": version: 2.15.0 resolution: "nan@npm:2.15.0" dependencies: @@ -22646,17 +22704,16 @@ __metadata: linkType: hard "react-konva@npm:^17.0.2-5": - version: 17.0.2-6 - resolution: "react-konva@npm:17.0.2-6" + version: 17.0.2-5 + resolution: "react-konva@npm:17.0.2-5" dependencies: - "@types/react-reconciler": ~0.26.2 react-reconciler: ~0.26.2 scheduler: ^0.20.2 peerDependencies: konva: ^8.0.1 || ^7.2.5 react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 5e868f6941090243c998f2817fbc9f031f60c83e236dc3f6328c904114582cfe281a08df9b5146b3339f6e1ccf30f3707d03de85fd534fb42fbe0ee6c6531b0c + checksum: 614522753fe95322fc022569cd95443eacfc1b9d2d84c0bb4ea40ce6cdce9b7c5843268e67ebef7cdb6d50ab08b8a5038ec760c3977a105e233bcceb8408de56 languageName: node linkType: hard @@ -24382,6 +24439,17 @@ __metadata: languageName: node linkType: hard +"simple-get@npm:^3.0.3": + version: 3.1.1 + resolution: "simple-get@npm:3.1.1" + dependencies: + decompress-response: ^4.2.0 + once: ^1.3.1 + simple-concat: ^1.0.0 + checksum: 80195e70bf171486e75c31e28e5485468195cc42f85940f8b45c4a68472160144d223eb4d07bc82ef80cb974b7c401db021a540deb2d34ac4b3b8883da2d6401 + languageName: node + linkType: hard + "simple-get@npm:^4.0.0, simple-get@npm:^4.0.1": version: 4.0.1 resolution: "simple-get@npm:4.0.1" @@ -25542,7 +25610,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.0.2, tar@npm:^6.1.2": +"tar@npm:^6.0.2, tar@npm:^6.1.0, tar@npm:^6.1.2": version: 6.1.11 resolution: "tar@npm:6.1.11" dependencies: