Skip to content
Open
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
1 change: 1 addition & 0 deletions __tests__/interface.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('Public Interface', () => {
'StyleSheet',
'Light',
'PointAnnotation',
'PointAnnotationManager',
'MarkerView',
'Annotation',
'Callout',
Expand Down
2 changes: 2 additions & 0 deletions android/src/main/java/com/rnmapbox/rnmbx/RNMBXPackage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.rnmapbox.rnmbx.components.annotation.RNMBXCalloutManager
import com.rnmapbox.rnmbx.components.annotation.RNMBXMarkerViewContentManager
import com.rnmapbox.rnmbx.components.annotation.RNMBXMarkerViewManager
import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationManager
import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationManagerViewManager
import com.rnmapbox.rnmbx.components.annotation.RNMBXPointAnnotationModule
import com.rnmapbox.rnmbx.components.camera.RNMBXCameraManager
import com.rnmapbox.rnmbx.components.camera.RNMBXCameraModule
Expand Down Expand Up @@ -135,6 +136,7 @@ class RNMBXPackage : TurboReactPackage() {
managers.add(RNMBXMarkerViewManager(reactApplicationContext))
managers.add(RNMBXMarkerViewContentManager(reactApplicationContext))
managers.add(RNMBXPointAnnotationManager(reactApplicationContext, getViewTagResolver(reactApplicationContext, "RNMBXPointAnnotationManager")))
managers.add(RNMBXPointAnnotationManagerViewManager(reactApplicationContext))
managers.add(RNMBXCalloutManager())
managers.add(RNMBXNativeUserLocationManager())
managers.add(RNMBXCustomLocationProviderManager())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.rnmapbox.rnmbx.components.annotation

import android.content.Context
import com.rnmapbox.rnmbx.components.AbstractMapFeature
import com.rnmapbox.rnmbx.components.RemovalReason
import com.rnmapbox.rnmbx.components.mapview.RNMBXMapView

class RNMBXPointAnnotationManagerView(context: Context) : AbstractMapFeature(context) {
var slot: String? = null
set(value) {
field = value
applySlot()
}

private fun applySlot() {
withMapView { mapView ->
slot?.let { mapView.pointAnnotations?.manager?.slot = it }
?: run { mapView.pointAnnotations?.manager?.slot = null }
}
}

override fun addToMap(mapView: RNMBXMapView) {
super.addToMap(mapView)
applySlot()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.rnmapbox.rnmbx.components.annotation

import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.common.MapBuilder
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.viewmanagers.RNMBXPointAnnotationManagerManagerInterface
import com.rnmapbox.rnmbx.components.AbstractEventEmitter

class RNMBXPointAnnotationManagerViewManager(context: ReactApplicationContext) :
AbstractEventEmitter<RNMBXPointAnnotationManagerView>(context),
RNMBXPointAnnotationManagerManagerInterface<RNMBXPointAnnotationManagerView> {
override fun customEvents(): Map<String, String>? {
return MapBuilder.builder<String, String>().build()
}

override fun getName(): String {
return REACT_CLASS
}

override fun createViewInstance(context: ThemedReactContext): RNMBXPointAnnotationManagerView {
return RNMBXPointAnnotationManagerView(context)
}

companion object {
const val REACT_CLASS = "RNMBXPointAnnotationManager"
}

@ReactProp(name = "slot")
override fun setSlot(view: RNMBXPointAnnotationManagerView, value: String?) {
view.slot = value
}
}
24 changes: 24 additions & 0 deletions docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -6529,6 +6529,30 @@
"relPath": "src/components/PointAnnotation.tsx",
"name": "PointAnnotation"
},
"PointAnnotationManager": {
"description": "Configures the shared PointAnnotation manager for the parent MapView.\nWrap PointAnnotation components as children.",
"displayName": "PointAnnotationManager",
"methods": [],
"props": [
{
"name": "slot",
"required": false,
"type": "'bottom' \\| 'middle' \\| 'top' \\| (string & {})",
"default": "none",
"description": "The slot in the style layer stack to position the annotation layer.\nUse with Mapbox Standard style to control layer ordering."
},
{
"name": "children",
"required": false,
"type": "ReactNode",
"default": "none",
"description": "FIX ME NO DESCRIPTION"
}
],
"fileNameWithExt": "PointAnnotationManager.tsx",
"relPath": "src/components/PointAnnotationManager.tsx",
"name": "PointAnnotationManager"
},
"Rain": {
"description": "",
"displayName": "Rain",
Expand Down
91 changes: 91 additions & 0 deletions example/src/examples/Annotations/PointAnnotationManagerSlot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import {
Camera,
MapView,
PointAnnotation,
PointAnnotationManager,
} from '@rnmapbox/maps';
import { Button } from '@rneui/base';

import { ExampleWithMetadata } from '../common/ExampleMetadata'; // exclude-from-doc

const styles = StyleSheet.create({
map: { flex: 1 },
pin: {
width: 30,
height: 30,
borderRadius: 15,
justifyContent: 'center',
alignItems: 'center',
},
label: { color: 'white', fontWeight: 'bold', fontSize: 12 },
buttons: {
flexDirection: 'row',
justifyContent: 'center',
padding: 8,
gap: 8,
},
});

const COORDS: [number, number][] = [
[-74.00597, 40.71427],
[-74.0065, 40.7128],
[-74.0045, 40.7155],
];

const PointAnnotationManagerSlot = () => {
const [slot, setSlot] = useState<string>('middle');

return (
<>
<MapView style={styles.map} styleURL="mapbox://styles/mapbox/standard">
<Camera
defaultSettings={{
centerCoordinate: [-74.00597, 40.71427],
zoomLevel: 15,
pitch: 45,
}}
/>
<PointAnnotationManager slot={slot}>
{COORDS.map((coord, i) => (
<PointAnnotation key={`pin-${i}`} id={`pin-${i}`} coordinate={coord}>
<View style={[styles.pin, { backgroundColor: 'dodgerblue' }]}>
<Text style={styles.label}>{i + 1}</Text>
</View>
</PointAnnotation>
))}
</PointAnnotationManager>
</MapView>
<View style={styles.buttons}>
<Button
title="bottom"
onPress={() => setSlot('bottom')}
color={slot === 'bottom' ? 'primary' : 'grey'}
/>
<Button
title="middle"
onPress={() => setSlot('middle')}
color={slot === 'middle' ? 'primary' : 'grey'}
/>
<Button
title="top"
onPress={() => setSlot('top')}
color={slot === 'top' ? 'primary' : 'grey'}
/>
</View>
</>
);
};

export default PointAnnotationManagerSlot;

const metadata: ExampleWithMetadata['metadata'] = {
title: 'PointAnnotationManager Slot',
tags: ['PointAnnotationManager', 'PointAnnotation', 'slot'],
docs: `
Demonstrates using PointAnnotationManager to position annotations
in different slots of the Mapbox Standard style.
`,
};
PointAnnotationManagerSlot.metadata = metadata;
1 change: 1 addition & 0 deletions example/src/examples/Annotations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { default as CustomCallout } from './CustomCallout';
export { default as Heatmap } from './Heatmap';
export { default as MarkerView } from './MarkerView';
export { default as PointAnnotationAnchors } from './PointAnnotationAnchors';
export { default as PointAnnotationManagerSlot } from './PointAnnotationManagerSlot';
export { default as ShowPointAnnotation } from './ShowPointAnnotation';

export const metadata = {
Expand Down
15 changes: 15 additions & 0 deletions ios/RNMBX/RNMBXPointAnnotationManagerComponentView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#ifdef __cplusplus

#import <UIKit/UIKit.h>

#import <React/RCTUIManager.h>
#import <React/RCTViewComponentView.h>

NS_ASSUME_NONNULL_BEGIN

@interface RNMBXPointAnnotationManagerComponentView : RCTViewComponentView

@end

NS_ASSUME_NONNULL_END
#endif // __cplusplus
72 changes: 72 additions & 0 deletions ios/RNMBX/RNMBXPointAnnotationManagerComponentView.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@

#import "RNMBXPointAnnotationManagerComponentView.h"
#import "RNMBXFabricHelpers.h"
#import "RNMBXFabricPropConvert.h"

#import <React/RCTConversions.h>
#import <React/RCTFabricComponentsPlugins.h>

#import <react/renderer/components/rnmapbox_maps_specs/ComponentDescriptors.h>
#import <react/renderer/components/rnmapbox_maps_specs/EventEmitters.h>
#import <react/renderer/components/rnmapbox_maps_specs/Props.h>
#import <react/renderer/components/rnmapbox_maps_specs/RCTComponentViewHelpers.h>

#import "rnmapbox_maps-Swift.pre.h"

using namespace facebook::react;

@interface RNMBXPointAnnotationManagerComponentView () <RCTRNMBXPointAnnotationManagerViewProtocol>
@end

@implementation RNMBXPointAnnotationManagerComponentView {
RNMBXPointAnnotationManagerView *_view;
}

// Needed because of this: https://github.com/facebook/react-native/pull/37274
+ (void)load {
[super load];
}

- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
static const auto defaultProps =
std::make_shared<const RNMBXPointAnnotationManagerProps>();
_props = defaultProps;
[self prepareView];
}

return self;
}

- (void)prepareView {
_view = [[RNMBXPointAnnotationManagerView alloc] init];
self.contentView = _view;
}

#pragma mark - RCTComponentViewProtocol

+ (ComponentDescriptorProvider)componentDescriptorProvider {
return concreteComponentDescriptorProvider<
RNMBXPointAnnotationManagerComponentDescriptor>();
}

- (void)updateProps:(const Props::Shared &)props
oldProps:(const Props::Shared &)oldProps {
const auto &oldViewProps = static_cast<const RNMBXPointAnnotationManagerProps &>(*_props);
const auto &newViewProps = static_cast<const RNMBXPointAnnotationManagerProps &>(*props);

RNMBX_OPTIONAL_PROP_NSString(slot)

[super updateProps:props oldProps:oldProps];
}

- (void)prepareForRecycle {
[super prepareForRecycle];
[self prepareView];
}

@end

Class<RCTComponentViewProtocol> RNMBXPointAnnotationManagerCls(void) {
return RNMBXPointAnnotationManagerComponentView.class;
}
21 changes: 21 additions & 0 deletions ios/RNMBX/RNMBXPointAnnotationManagerComponentView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import MapboxMaps

@objc(RNMBXPointAnnotationManagerView)
open class RNMBXPointAnnotationManagerView: RNMBXMapComponentBase {
@objc public var slot: String? = nil {
didSet {
applySlot()
}
}

private func applySlot() {
withRNMBXMapView { map in
map.pointAnnotationManager.manager.slot = self.slot
}
}

public override func addToMap(_ map: RNMBXMapView, style: Style) {
super.addToMap(map, style: style)
applySlot()
}
}
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@
"RNMBXNativeUserLocation": {
"className": "RNMBXNativeUserLocationComponentView"
},
"RNMBXPointAnnotationManager": {
"className": "RNMBXPointAnnotationManagerComponentView"
},
"RNMBXPointAnnotation": {
"className": "RNMBXPointAnnotationComponentView"
},
Expand Down Expand Up @@ -328,6 +331,7 @@
"RNMBXModelLayer": "RNMBXModelLayerComponentView",
"RNMBXModels": "RNMBXModelsComponentView",
"RNMBXNativeUserLocation": "RNMBXNativeUserLocationComponentView",
"RNMBXPointAnnotationManager": "RNMBXPointAnnotationManagerComponentView",
"RNMBXPointAnnotation": "RNMBXPointAnnotationComponentView",
"RNMBXRain": "RNMBXRainComponentView",
"RNMBXRasterArraySource": "RNMBXRasterArraySourceComponentView",
Expand Down
1 change: 1 addition & 0 deletions src/Mapbox.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export {
} from './components/MapView';
export { default as Light } from './components/Light';
export { default as PointAnnotation } from './components/PointAnnotation';
export { default as PointAnnotationManager } from './components/PointAnnotationManager';
export { default as Annotation } from './components/Annotation';
export { default as Callout } from './components/Callout';
export { default as StyleImport } from './components/StyleImport';
Expand Down
30 changes: 30 additions & 0 deletions src/components/PointAnnotationManager.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { type ReactNode } from 'react';

import NativePointAnnotationManager from '../specs/RNMBXPointAnnotationManagerNativeComponent';

type Slot = 'bottom' | 'middle' | 'top';

type Props = {
/**
* The slot in the style layer stack to position the annotation layer.
* Use with Mapbox Standard style to control layer ordering.
*/
slot?: Slot | (string & {});

children?: ReactNode;
};

/**
* Configures the shared PointAnnotation manager for the parent MapView.
* Wrap PointAnnotation components as children.
*/
const PointAnnotationManager = (props: Props) => {
return (
<>
<NativePointAnnotationManager slot={props.slot as Slot | undefined} />
{props.children}
</>
);
};

export default PointAnnotationManager;
Loading
Loading