Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add explicit type for exported function components #611

Merged
merged 1 commit into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/components/__tests__/map-control.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import '@testing-library/jest-dom';

import React, {ReactElement} from 'react';
import React, {FunctionComponent, PropsWithChildren} from 'react';
import {initialize} from '@googlemaps/jest-mocks';
import {cleanup, render} from '@testing-library/react';

Expand All @@ -11,12 +11,12 @@ import {waitForMockInstance} from './__utils__/wait-for-mock-instance';

jest.mock('../../libraries/google-maps-api-loader');

let wrapper: ({children}: {children: React.ReactNode}) => ReactElement | null;
let wrapper: FunctionComponent<PropsWithChildren>;

beforeEach(() => {
initialize();

wrapper = ({children}: {children: React.ReactNode}) => (
wrapper = ({children}) => (
<APIProvider apiKey={'apikey'}>
<Map zoom={10} center={{lat: 0, lng: 0}}>
{children}
Expand Down
6 changes: 3 additions & 3 deletions src/components/__tests__/map.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {FunctionComponent, PropsWithChildren} from 'react';
import {render, screen, waitFor} from '@testing-library/react';
import {initialize, mockInstances} from '@googlemaps/jest-mocks';
import '@testing-library/jest-dom';
Expand All @@ -9,7 +9,7 @@ import {APILoadingStatus} from '../../libraries/api-loading-status';

jest.mock('../../libraries/google-maps-api-loader');

let wrapper: ({children}: {children: React.ReactNode}) => JSX.Element | null;
let wrapper: FunctionComponent<PropsWithChildren>;
let mockContextValue: jest.MockedObject<APIProviderContextValue>;
let createMapSpy: jest.Mock<
void,
Expand All @@ -29,7 +29,7 @@ beforeEach(() => {
clearMapInstances: jest.fn()
};

wrapper = ({children}: {children: React.ReactNode}) => (
wrapper = ({children}) => (
<APIProviderContext.Provider value={mockContextValue}>
{children}
</APIProviderContext.Provider>
Expand Down
6 changes: 3 additions & 3 deletions src/components/__tests__/marker.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, {FunctionComponent, PropsWithChildren} from 'react';
import {initialize, mockInstances} from '@googlemaps/jest-mocks';
import {cleanup, render, waitFor} from '@testing-library/react';

Expand All @@ -9,15 +9,15 @@ import MockedFunction = jest.MockedFunction;

jest.mock('../../libraries/google-maps-api-loader');

let wrapper: ({children}: {children: React.ReactNode}) => JSX.Element | null;
let wrapper: FunctionComponent<PropsWithChildren>;
let createMarkerSpy: jest.Mock;

beforeEach(() => {
// initialize the Maps JavaScript API mocks
initialize();

// Create wrapper component
wrapper = ({children}: {children: React.ReactNode}) => (
wrapper = ({children}) => (
<APIProvider apiKey={'apikey'}>
<GoogleMap zoom={10} center={{lat: 0, lng: 0}}>
{children}
Expand Down
6 changes: 3 additions & 3 deletions src/components/__tests__/pin.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {JSX} from 'react';
import React, {FunctionComponent, PropsWithChildren} from 'react';
import {initialize, mockInstances} from '@googlemaps/jest-mocks';
import {cleanup, render} from '@testing-library/react';

Expand All @@ -11,7 +11,7 @@ import {waitForSpy} from './__utils__/wait-for-spy';

jest.mock('../../libraries/google-maps-api-loader');

let wrapper: ({children}: {children: React.ReactNode}) => JSX.Element | null;
let wrapper: FunctionComponent<PropsWithChildren>;

let createMarkerSpy: jest.Mock<
void,
Expand All @@ -26,7 +26,7 @@ beforeEach(() => {
initialize();

// Create wrapper component
wrapper = ({children}: {children: React.ReactNode}) => (
wrapper = ({children}) => (
<APIProvider apiKey={'apikey'} libraries={['places']}>
<GoogleMap zoom={10} center={{lat: 0, lng: 0}}>
{children}
Expand Down
8 changes: 4 additions & 4 deletions src/components/advanced-marker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, {
Children,
CSSProperties,
forwardRef,
ForwardRefExoticComponent,
useCallback,
useEffect,
useImperativeHandle,
Expand Down Expand Up @@ -254,8 +255,8 @@ function useAdvancedMarker(props: AdvancedMarkerProps) {
return [marker, contentContainer] as const;
}

export const AdvancedMarker = forwardRef(
(props: AdvancedMarkerProps, ref: Ref<AdvancedMarkerRef>) => {
export const AdvancedMarker: ForwardRefExoticComponent<AdvancedMarkerProps> =
forwardRef((props, ref: Ref<AdvancedMarkerRef>) => {
const {children, style, className, anchorPoint} = props;
const [marker, contentContainer] = useAdvancedMarker(props);

Expand All @@ -279,8 +280,7 @@ export const AdvancedMarker = forwardRef(
)}
</AdvancedMarkerContext.Provider>
);
}
);
});

export function useAdvancedMarkerRef() {
const [marker, setMarker] =
Expand Down
10 changes: 4 additions & 6 deletions src/components/api-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {
FunctionComponent,
PropsWithChildren,
ReactElement,
useCallback,
useEffect,
useMemo,
Expand Down Expand Up @@ -33,7 +33,7 @@ const DEFAULT_SOLUTION_CHANNEL = 'GMP_visgl_rgmlibrary_v1_default';
export const APIProviderContext =
React.createContext<APIProviderContextValue | null>(null);

export type APIProviderProps = {
export type APIProviderProps = PropsWithChildren<{
/**
* apiKey must be provided to load the Google Maps JavaScript API. To create an API key, see: https://developers.google.com/maps/documentation/javascript/get-api-key
* Part of:
Expand Down Expand Up @@ -89,7 +89,7 @@ export type APIProviderProps = {
* A function that will be called if there was an error when loading the Google Maps JavaScript API.
*/
onError?: (error: unknown) => void;
};
}>;

/**
* local hook to set up the map-instance management context.
Expand Down Expand Up @@ -225,9 +225,7 @@ function useGoogleMapsApiLoader(props: APIProviderProps) {
/**
* Component to wrap the components from this library and load the Google Maps JavaScript API
*/
export const APIProvider = (
props: PropsWithChildren<APIProviderProps>
): ReactElement | null => {
export const APIProvider: FunctionComponent<APIProviderProps> = props => {
const {children, ...loaderProps} = props;
const {mapInstances, addMapInstance, removeMapInstance, clearMapInstances} =
useMapInstances();
Expand Down
5 changes: 4 additions & 1 deletion src/components/info-window.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable complexity */
import React, {
CSSProperties,
FunctionComponent,
PropsWithChildren,
ReactNode,
useEffect,
Expand Down Expand Up @@ -34,7 +35,9 @@ export type InfoWindowProps = Omit<
/**
* Component to render an Info Window with the Maps JavaScript API
*/
export const InfoWindow = (props: PropsWithChildren<InfoWindowProps>) => {
export const InfoWindow: FunctionComponent<
PropsWithChildren<InfoWindowProps>
> = props => {
const {
// content options
children,
Expand Down
7 changes: 5 additions & 2 deletions src/components/map-control.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useEffect, useMemo} from 'react';
import {FunctionComponent, useEffect, useMemo} from 'react';
import {createPortal} from 'react-dom';
import {useMap} from '../hooks/use-map';

Expand Down Expand Up @@ -46,7 +46,10 @@ export const ControlPosition = {
export type ControlPosition =
(typeof ControlPosition)[keyof typeof ControlPosition];

export const MapControl = ({children, position}: MapControlProps) => {
export const MapControl: FunctionComponent<MapControlProps> = ({
children,
position
}) => {
const controlContainer = useMemo(() => document.createElement('div'), []);
const map = useMap();

Expand Down
4 changes: 2 additions & 2 deletions src/components/map/auth-failure-message.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, {CSSProperties} from 'react';
import React, {CSSProperties, FunctionComponent} from 'react';

export const AuthFailureMessage = () => {
export const AuthFailureMessage: FunctionComponent = () => {
const style: CSSProperties = {
position: 'absolute',
top: 0,
Expand Down
114 changes: 59 additions & 55 deletions src/components/map/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable complexity */
import React, {
CSSProperties,
FunctionComponent,
PropsWithChildren,
useContext,
useEffect,
Expand Down Expand Up @@ -63,61 +64,60 @@ export type RenderingType = (typeof RenderingType)[keyof typeof RenderingType];
/**
* Props for the Map Component
*/
export type MapProps = Omit<
google.maps.MapOptions,
'renderingType' | 'colorScheme'
> &
MapEventProps &
DeckGlCompatProps & {
/**
* An id for the map, this is required when multiple maps are present
* in the same APIProvider context.
*/
id?: string;

/**
* Additional style rules to apply to the map dom-element.
*/
style?: CSSProperties;

/**
* Additional css class-name to apply to the element containing the map.
*/
className?: string;

/**
* The color-scheme to use for the map.
*/
colorScheme?: ColorScheme;

/**
* The rendering-type to be used.
*/
renderingType?: RenderingType;

/**
* Indicates that the map will be controlled externally. Disables all controls provided by the map itself.
*/
controlled?: boolean;

/**
* Enable caching of map-instances created by this component.
*/
reuseMaps?: boolean;

defaultCenter?: google.maps.LatLngLiteral;
defaultZoom?: number;
defaultHeading?: number;
defaultTilt?: number;
/**
* Alternative way to specify the default camera props as a geographic region that should be fully visible
*/
defaultBounds?: google.maps.LatLngBoundsLiteral & {
padding?: number | google.maps.Padding;
};
};
export type MapProps = PropsWithChildren<
Omit<google.maps.MapOptions, 'renderingType' | 'colorScheme'> &
MapEventProps &
DeckGlCompatProps & {
/**
* An id for the map, this is required when multiple maps are present
* in the same APIProvider context.
*/
id?: string;

/**
* Additional style rules to apply to the map dom-element.
*/
style?: CSSProperties;

/**
* Additional css class-name to apply to the element containing the map.
*/
className?: string;

/**
* The color-scheme to use for the map.
*/
colorScheme?: ColorScheme;

/**
* The rendering-type to be used.
*/
renderingType?: RenderingType;

/**
* Indicates that the map will be controlled externally. Disables all controls provided by the map itself.
*/
controlled?: boolean;

/**
* Enable caching of map-instances created by this component.
*/
reuseMaps?: boolean;

defaultCenter?: google.maps.LatLngLiteral;
defaultZoom?: number;
defaultHeading?: number;
defaultTilt?: number;
/**
* Alternative way to specify the default camera props as a geographic region that should be fully visible
*/
defaultBounds?: google.maps.LatLngBoundsLiteral & {
padding?: number | google.maps.Padding;
};
}
>;

export const Map = (props: PropsWithChildren<MapProps>) => {
export const Map: FunctionComponent<MapProps> = (props: MapProps) => {
const {children, id, className, style} = props;
const context = useContext(APIProviderContext);
const loadingStatus = useApiLoadingStatus();
Expand Down Expand Up @@ -240,4 +240,8 @@ export const Map = (props: PropsWithChildren<MapProps>) => {
</div>
);
};
Map.deckGLViewProps = true;

// The deckGLViewProps flag here indicates to deck.gl that the Map component is
// able to handle viewProps from deck.gl when deck.gl is used to control the map.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(Map as any).deckGLViewProps = true;
13 changes: 8 additions & 5 deletions src/components/marker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable complexity */
import React, {
forwardRef,
ForwardRefExoticComponent,
useCallback,
useEffect,
useImperativeHandle,
Expand Down Expand Up @@ -118,13 +119,15 @@ function useMarker(props: MarkerProps) {
/**
* Component to render a marker on a map
*/
export const Marker = forwardRef((props: MarkerProps, ref: MarkerRef) => {
const marker = useMarker(props);
export const Marker: ForwardRefExoticComponent<MarkerProps> = forwardRef(
(props: MarkerProps, ref: MarkerRef) => {
const marker = useMarker(props);

useImperativeHandle(ref, () => marker, [marker]);
useImperativeHandle(ref, () => marker, [marker]);

return <></>;
});
return <></>;
}
);

export function useMarkerRef() {
const [marker, setMarker] = useState<google.maps.Marker | null>(null);
Expand Down
5 changes: 3 additions & 2 deletions src/components/pin.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Children,
FunctionComponent,
PropsWithChildren,
useContext,
useEffect,
Expand All @@ -12,12 +13,12 @@ import {logErrorOnce} from '../libraries/errors';
/**
* Props for the Pin component
*/
export type PinProps = google.maps.marker.PinElementOptions;
export type PinProps = PropsWithChildren<google.maps.marker.PinElementOptions>;

/**
* Component to configure the appearance of an AdvancedMarker
*/
export const Pin = (props: PropsWithChildren<PinProps>) => {
export const Pin: FunctionComponent<PinProps> = props => {
const advancedMarker = useContext(AdvancedMarkerContext)?.marker;
const glyphContainer = useMemo(() => document.createElement('div'), []);

Expand Down
Loading