Skip to content
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
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ The [example app](/example/) demonstrates usage of the library. You need to run

It is configured to use the local version of the library, so any changes you make to the library's source code will be reflected in the example app. Changes to the library's JavaScript code will be reflected in the example app without a rebuild, but native code changes will require a rebuild of the example app.

If you want to use Android Studio or XCode to edit the native code, you can open the `example/android` or `example/ios` directories respectively in those editors. To edit the Objective-C or Swift files, open `example/ios/YamapLiteExample.xcworkspace` in XCode and find the source files at `Pods > Development Pods > react-native-yamap-lite`.
If you want to use Android Studio or XCode to edit the native code, you can open the `example/android` or `example/ios` directories respectively in those editors. To edit the Objective-C or Swift files, open `example/ios/YamapLiteExample.xcworkspace` in XCode and find the source files at `Pods > Development Pods > @atc/react-native-yamap-lite`.

To edit the Java or Kotlin files, open `example/android` in Android studio and find the source files at `react-native-yamap-lite` under `Android`.
To edit the Java or Kotlin files, open `example/android` in Android studio and find the source files at `@atc/react-native-yamap-lite` under `Android`.

You can use various commands from the root directory to work with the project.

Expand Down
156 changes: 98 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
# React Native Yandex Maps Lite (Яндекс Карты Lite)
<div align="center">

Легковесная библиотека для интеграции Yandex Maps (Яндекс Карт) в React Native. Lite версия без маршрутов, геокодера и поиска.
<img src="./images/banner.png" alt="@atc/react-native-yamap-lite" width="420" />

# @atc/react-native-yamap-lite

**Легковесная библиотека для интеграции Yandex Maps (Яндекс Карт) в React Native.**

Yandex Maps · React Native · Fabric

[![npm](https://img.shields.io/npm/v/@atc/react-native-yamap-lite.svg)](https://www.npmjs.com/package/@atc/react-native-yamap-lite)
[![platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20Android-blue.svg)](#требования)
[![New Architecture](https://img.shields.io/badge/New%20Architecture-Fabric-success.svg)](#требования)
[![tests](https://img.shields.io/badge/tests-Jest%20%2B%20Harness-brightgreen.svg)](#тесты)
[![license](https://img.shields.io/npm/l/@atc/react-native-yamap-lite.svg)](./LICENSE)

</div>

---

Lite-обёртка над [Yandex MapKit SDK](https://yandex.ru/dev/maps/mapkit/) — карты, маркеры,
круги, полигоны, полилинии и кластеризация без лишнего веса: в ней нет маршрутов,
геокодера и поиска, только то, что нужно для отображения карты в приложении.

Библиотека собрана целиком на **новой архитектуре React Native** (**Fabric** +
**TurboModules**), что даёт нативную скорость рендеринга на iOS и Android.

## ✨ Возможности

- 🗺️ **Карты Yandex** — типы `map` / `satellite` / `hybrid`, ночной режим, кастомные стили MapKit.
- 📍 **Маркеры** — локальные (`require`) и удалённые (`{ uri }`) изображения, якорь, масштаб, z-index.
- ⭕ **Круги, полигоны, полилинии** — оверлеи с настраиваемыми цветами заливки и обводки.
- 🔗 **Кластеризация** — компонент `ClusteredYamap` для автоматической группировки маркеров.
- 📱 **Позиция пользователя** — отслеживание геолокации, кастомная иконка и зона точности.
- 🎯 **Управление камерой** — `setCenter`, `setZoom`, `fitAllMarkers`, чтение позиции и видимой области через `ref`.
- 🎨 **Жесты и UI** — гибкая настройка жестов, частоты кадров и позиции логотипа Яндекса.

> 💡 Знакомы с [`react-native-yamap`](https://github.com/volga-volga/react-native-yamap)?
> API близок по духу — миграция требует минимальных изменений.

## Требования

Expand All @@ -11,13 +47,13 @@
## Установка

```sh
yarn add react-native-yamap-lite
yarn add @atc/react-native-yamap-lite
```

или

```sh
npm install react-native-yamap-lite --save
npm install @atc/react-native-yamap-lite --save
```

### iOS
Expand All @@ -30,72 +66,43 @@ cd ios && pod install && cd ..

## Инициализация карт

### iOS

**Обязательно** инициализировать MapKit в функции `didFinishLaunchingWithOptions` в `AppDelegate.swift`:

```swift
import YandexMapsMobile
Инициализация выполняется **полностью из JavaScript** — не нужно править
`AppDelegate.swift` или `MainApplication`. Достаточно один раз вызвать
`YamapUtils.init(apiKey)` до того, как карта отрендерится (например, в `index.js`
или в корне `App.tsx`). Этот вызов сам устанавливает API-ключ и запускает MapKit
на обеих платформах.

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
```js
// index.js
import { AppRegistry } from 'react-native';
import { YamapUtils } from '@atc/react-native-yamap-lite';
import App from './App';
import { name as appName } from './app.json';

reactNativeDelegate = delegate
reactNativeFactory = factory
// Замените на ваш API-ключ от Yandex MapKit
YamapUtils.init('YOUR_API_KEY').catch((error) => {
console.warn('YamapUtils.init failed:', error);
});

// Инициализуйте SDK Yandex Maps перед стартом React Native
YMKMapKit.setLocale("ru_RU")
YMKMapKit.setApiKey("YOUR_API_KEY")
YMKMapKit.initialize()

window = UIWindow(frame: UIScreen.main.bounds)
// (необязательно) язык интерфейса карты
YamapUtils.setLocale('ru_RU');

// ... остальной код инициализации

return true
}
AppRegistry.registerComponent(appName, () => App);
```

### Android

Инициализируйте MapKit в методе `onCreate` класса `MainApplication`:
> 💡 `init` возвращает `Promise` — карту можно рендерить сразу, она дождётся
> завершения инициализации. Метод идемпотентен: повторные вызовы безопасны.

**ВАЖНО:** Замените `YOUR_API_KEY` на ваш API ключ от Yandex MapKit.

```kotlin
import com.yandex.mapkit.MapKitFactory

class MainApplication : Application() {
override fun onCreate() {
super.onCreate()

MapKitFactory.setLocale("ru_RU")
MapKitFactory.setApiKey("YOUR_API_KEY")
MapKitFactory.initialize(applicationContext)

// ... остальной код инициализации
}
}
```

Добавьте в вашем проекте зависимость в `android/app/build.gradle`

```gradle
dependencies {
implementation('com.yandex.android:maps.mobile:4.24.0-lite')
...
}
```
> ℹ️ Android-зависимость MapKit (`com.yandex.android:maps.mobile`) уже входит в
> библиотеку — добавлять её в `android/app/build.gradle` вручную не нужно.

## Использование

### Базовый пример

```jsx
import React from 'react';
import { YaMap, Marker, Circle } from 'react-native-yamap-lite';
import { YaMap, Marker, Circle } from '@atc/react-native-yamap-lite';

const Map = () => {
return (
Expand Down Expand Up @@ -232,14 +239,18 @@ interface YaMapRef {
animation?: 'LINEAR' | 'SMOOTH'
) => void;
fitAllMarkers: () => void;
getMapObjectCount: () => Promise<number>;
getVisibleRegion: () => Promise<VisibleRegion>;
getScreenPoints: (points: Point[]) => Promise<ScreenPoint[]>;
getWorldPoints: (points: ScreenPoint[]) => Promise<Point[]>;
}
```

**Пример использования:**

```jsx
import React, { useRef } from 'react';
import { YaMap } from 'react-native-yamap-lite';
import { YaMap } from '@atc/react-native-yamap-lite';

const Map = () => {
const mapRef = useRef(null);
Expand Down Expand Up @@ -341,7 +352,7 @@ const Map = () => {
Компонент для отображения кластеризованных маркеров:

```jsx
import { ClusteredYamap, Marker } from 'react-native-yamap-lite';
import { ClusteredYamap, Marker } from '@atc/react-native-yamap-lite';

<ClusteredYamap
clusterColor="#ff00ff"
Expand Down Expand Up @@ -392,6 +403,35 @@ yarn android

**Примечание:** Все методы и примеры использования карты можно запустить и посмотреть в папке `example` проекта.

## Тесты

Библиотека покрыта тестами на двух уровнях:

- **Jest** — модульные тесты JS-слоя (компоненты, парсинг пропсов, преобразование
координат, мосты к нативным модулям). Запускаются без устройства/эмулятора:

```sh
yarn test
```

- **Harness** — интеграционные тесты, которые гоняют реальные нативные Fabric-компоненты
на **iOS и Android** через [`react-native-harness`](https://github.com/callstack/react-native-harness).
Покрыты `YaMap`, `Marker`, `Circle`, `Polygon`, `Polyline`, `ClusteredYamap`,
события карты, методы `YamapUtils` и набор регрессионных сценариев
(см. `example/harness/tests`):

```sh
# обе платформы
yarn test:harness

# по отдельности
yarn test:harness:ios
yarn test:harness:android
```

Так нативный код проверяется на настоящих картах, а не на моках, — это покрывает баги,
которые JS-тесты увидеть не могут.

## Важные замечания

1. Компонент карт стилизуется, как и `View` из React Native. Если карта не отображается, после инициализации с валидным ключом API, вероятно необходимо прописать стиль, который опишет размеры компонента (`height + width` или `flex`).
Expand Down
2 changes: 1 addition & 1 deletion example/harness/ensureMapKitInit.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { YamapUtils } from 'react-native-yamap-lite';
import { YamapUtils } from '@atc/react-native-yamap-lite';
import { YAMAP_API_KEY } from './constants';

/** @type {Promise<void> | null} */
Expand Down
2 changes: 1 addition & 1 deletion example/harness/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
type InitialRegion,
type YaMapProps,
type YaMapRef,
} from 'react-native-yamap-lite';
} from '@atc/react-native-yamap-lite';
import { INITIAL_REGION, MAP_LOAD_TIMEOUT } from './constants';
import { ensureMapKitInitialized } from './ensureMapKitInit';

Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/Circle.harness.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, test, expect } from 'react-native-harness';
import { Circle } from 'react-native-yamap-lite';
import { Circle } from '@atc/react-native-yamap-lite';
import { MOSCOW } from '../constants';
import { renderMapWithOverlays, renderUpdatingOverlays } from '../helpers';

Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/ClusteredYamap.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
Marker,
type ClusteredYamapProps,
type YaMapRef,
} from 'react-native-yamap-lite';
} from '@atc/react-native-yamap-lite';
import { CAMERA_ANIMATION_TIMEOUT, INITIAL_REGION, MOSCOW } from '../constants';
import { ensureMapKitInitialized } from '../ensureMapKitInit';
import { waitForMapReady, expectNear } from '../helpers';
Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/MapEvents.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
type YaMapRef,
type CameraPosition,
type MapLoaded,
} from 'react-native-yamap-lite';
} from '@atc/react-native-yamap-lite';
import {
INITIAL_REGION,
MOSCOW,
Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/Marker.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
YaMap,
type MarkerRef,
type YaMapRef,
} from 'react-native-yamap-lite';
} from '@atc/react-native-yamap-lite';
import { StyleSheet, View } from 'react-native';
import { INITIAL_REGION, MOSCOW } from '../constants';
import { ensureMapKitInitialized } from '../ensureMapKitInit';
Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/Polygon.harness.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, test, expect } from 'react-native-harness';
import { Polygon } from 'react-native-yamap-lite';
import { Polygon } from '@atc/react-native-yamap-lite';
import { MOSCOW } from '../constants';
import { renderMapWithOverlays, renderUpdatingOverlays } from '../helpers';

Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/Polyline.harness.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, test, expect } from 'react-native-harness';
import { Polyline } from 'react-native-yamap-lite';
import { Polyline } from '@atc/react-native-yamap-lite';
import { MOSCOW } from '../constants';
import { renderMapWithOverlays, renderUpdatingOverlays } from '../helpers';

Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/Regression.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
YaMap,
YamapUtils,
type YaMapRef,
} from 'react-native-yamap-lite';
} from '@atc/react-native-yamap-lite';
import {
CAMERA_ANIMATION_TIMEOUT,
INITIAL_REGION,
Expand Down Expand Up @@ -326,7 +326,7 @@
expect(typeof locale).toBe('string');

// Suppress unused variable lint — we only care that no hard crash occurred
void threw;

Check warning on line 329 in example/harness/tests/Regression.harness.tsx

View workflow job for this annotation

GitHub Actions / lint

Expected 'undefined' and instead saw 'void'
});
});

Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/UI.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
Marker,
YaMap,
type YaMapRef,
} from 'react-native-yamap-lite';
} from '@atc/react-native-yamap-lite';
import { INITIAL_REGION, MOSCOW } from '../constants';
import { ensureMapKitInitialized } from '../ensureMapKitInit';
import { waitForMapReady, expectNear } from '../helpers';
Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/YaMap.harness.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from 'react-native-harness';
import { useEffect, useState } from 'react';
import { StyleSheet, View } from 'react-native';
import { YaMap, type YaMapRef } from 'react-native-yamap-lite';
import { YaMap, type YaMapRef } from '@atc/react-native-yamap-lite';
import { CAMERA_ANIMATION_TIMEOUT, INITIAL_REGION, MOSCOW } from '../constants';
import { ensureMapKitInitialized } from '../ensureMapKitInit';
import { expectNear, renderMap, waitForMapReady } from '../helpers';
Expand Down
2 changes: 1 addition & 1 deletion example/harness/tests/YamapUtils.harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
afterEach,
} from 'react-native-harness';
import { Platform } from 'react-native';
import { YamapUtils } from 'react-native-yamap-lite';
import { YamapUtils } from '@atc/react-native-yamap-lite';
import { YAMAP_API_KEY } from '../constants';

describe('YamapUtils', () => {
Expand Down
4 changes: 2 additions & 2 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
"test:harness:android": "NODE_OPTIONS='--experimental-require-module' react-native-harness --harnessRunner android"
},
"dependencies": {
"@atc/react-native-yamap-lite": "link:..",
"react": "19.0.0",
"react-native": "0.79.2",
"react-native-yamap-lite": "link:.."
"react-native": "0.79.2"
},
"devDependencies": {
"@babel/core": "^7.25.2",
Expand Down
2 changes: 1 addition & 1 deletion example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
Circle,
Polygon,
Polyline,
} from 'react-native-yamap-lite';
} from '@atc/react-native-yamap-lite';
import { ensureMapKitInitialized } from '../harness/ensureMapKitInit';
import { markers } from './constants/markers';
import {
Expand Down
Binary file added images/banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-yamap-lite",
"version": "1.0.1",
"name": "@atc/react-native-yamap-lite",
"version": "1.0.0",
"description": "A lightweight wrapper for the Yandex MapKit SDK",
"main": "./src/index.tsx",
"types": "./src/index.tsx",
Expand Down Expand Up @@ -70,7 +70,8 @@
},
"homepage": "https://github.com/hydromoll/react-native-yamap-lite#readme",
"publishConfig": {
"registry": "https://registry.npmjs.org/"
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"devDependencies": {
"@commitlint/config-conventional": "^19.6.0",
Expand Down
2 changes: 1 addition & 1 deletion src/Utils/YamapUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Platform, NativeModules } from 'react-native';

const LINKING_ERROR =
`The package 'react-native-yamap-lite' doesn't seem to be linked. Make sure: \n\n` +
`The package '@atc/react-native-yamap-lite' doesn't seem to be linked. Make sure: \n\n` +
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
'- You rebuilt the app after installing the package\n' +
'- You are not using Expo managed workflow\n';
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"compilerOptions": {
"rootDir": ".",
"paths": {
"react-native-yamap-lite": ["./src/index"]
"@atc/react-native-yamap-lite": ["./src/index"]
},
"allowUnreachableCode": false,
"allowUnusedLabels": false,
Expand Down
Loading
Loading