commit 67c94197e14fc78b9fc5a559246cbbaef370d6d5 Author: Mathias Beaulieu-Duncan Date: Thu Sep 4 13:47:54 2025 -0400 initial commit diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..c97ccf2 --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +# Nested package.json's are only needed for development. +**/package.json \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..094e604 --- /dev/null +++ b/README.md @@ -0,0 +1,120 @@ +# ngx-open-map-wrapper + +An Angular 16+ library that provides a **unified map component** with automatic fallback between **MapLibre GL** (WebGL vector maps) and **Leaflet** (raster maps). + +It automatically chooses the best renderer for the user’s device: +- **MapLibre GL** if WebGL is supported +- **Leaflet** if WebGL is not available or raster rendering is forced + +--- + +## ✨ Features + +- 🗺️ Always shows a map — automatically picks the right engine for the device +- ⚡ Uses **MapLibre GL** for modern devices with WebGL support +- 🪶 Falls back to **Leaflet** for older or low‑end devices +- 🎯 Unified API for markers, zoom, and center — no need to learn two libraries +- 📱 Works seamlessly across desktop and mobile +- 🧩 Angular‑native: standalone components, signals, and modern syntax + +--- + +## 📦 Installation + +Install the library and its peer dependencies: + +```bash +yarn add ngx-open-open-map-wrapper leaflet maplibre-gl +``` + +Then import the required CSS styles in your global `styles.css` (or `styles.scss`): + +```css +@import "leaflet/dist/leaflet.css"; +@import "maplibre-gl/dist/maplibre-gl.css"; +``` + +--- + +## 🚀 Usage + +### Import the component + +Since the library is **standalone‑ready**, you can import the component directly: + +```ts +import { Component } from '@angular/core'; +import { MapComponent, MapFacade } from 'ngx-open-open-map-wrapper'; + +@Component({ + selector: 'app-root', + standalone: true, + imports: [MapComponent], + template: ` + + `, +}) +export class AppComponent { + private map?: MapFacade; + + onMapReady(facade: MapFacade) { + this.map = facade; + this.map.addMarker([46.3385, -72.6106], { color: 'blue' }); + } +} +``` + +--- + +## ⚙️ API + +### `MapComponent` Inputs +- `center: [lat, lng]` → Initial map center +- `zoom: number` → Initial zoom level +- `forceRaster: boolean` → Force Leaflet raster mode even if WebGL is available +- `styleUrl: string` → MapLibre style URL (default: MapLibre basic style) + +### `MapComponent` Outputs +- `(mapReady: MapFacade)` → Emits the `MapFacade` instance once the map is initialized + +--- + +### `MapFacade` Methods +- `setCenter([lat, lng])` → Move the map center +- `setZoom(zoom: number)` → Set zoom level +- `addMarker([lat, lng], { color?: string })` → Add a marker +- `destroy()` → Clean up map instance + +--- + +## 🧩 WebGL Detection Directive + +You can also use the directive directly if you want to check WebGL support: + +```html +
+ @if (webglOk) { + + } @else { +

WebGL not supported → fallback

+ } +
+``` + +```ts +webglOk = false; + +onWebGLCheck(supported: boolean) { + this.webglOk = supported; +} +``` + +--- + +## 📜 License + +MIT diff --git a/fesm2022/svrnty-ngx-open-map-wrapper.mjs b/fesm2022/svrnty-ngx-open-map-wrapper.mjs new file mode 100644 index 0000000..2da390a --- /dev/null +++ b/fesm2022/svrnty-ngx-open-map-wrapper.mjs @@ -0,0 +1,190 @@ +import { Map, NavigationControl, Marker } from 'maplibre-gl'; +import { Map as Map$1, TileLayer, Marker as Marker$1 } from 'leaflet'; +import * as i0 from '@angular/core'; +import { inject, PLATFORM_ID, output, Directive, Injector, input, runInInjectionContext, effect, ViewChild, Component } from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; + +function getLngLat(latLng) { + return [latLng[1], latLng[0]]; +} + +class LibreAdapter { + map; + init(container, options) { + this.map = new Map({ + container, + style: options.styleUrl, + center: getLngLat(options.center), + zoom: options.zoom, + }); + this.map.addControl(new NavigationControl(), 'top-right'); + } + setCenter(latLng) { + this.map.setCenter(getLngLat(latLng)); + } + setZoom(zoom) { + this.map.setZoom(zoom); + } + addMarker(latLng, options) { + new Marker({ color: options?.color || 'red' }) + .setLngLat(getLngLat(latLng)) + .addTo(this.map); + } + destroy() { + this.map.remove(); + } +} + +class LeafletAdapter { + map; + init(container, options) { + this.map = new Map$1(container).setView(options.center, options.zoom); + new TileLayer(options.tileUrl, { + attribution: '© OpenStreetMap contributors', + }).addTo(this.map); + } + setCenter(latLng) { + this.map.setView(latLng, this.map.getZoom()); + } + setZoom(zoom) { + this.map.setZoom(zoom); + } + addMarker(latLng, options) { + const marker = new Marker$1(latLng); + marker.addTo(this.map); + } + destroy() { + this.map.remove(); + } +} + +class MapFacade { + adapter; + leafletZoomOffset = 1; + constructor(forceRaster, webglAvailable) { + if (forceRaster || !webglAvailable) { + this.adapter = new LeafletAdapter(); + } + else { + this.adapter = new LibreAdapter(); + } + } + init(container, options) { + if (this.adapter instanceof LeafletAdapter) + options.zoom += this.leafletZoomOffset; + this.adapter.init(container, options); + } + setCenter(latLng) { + this.adapter.setCenter(latLng); + } + setZoom(zoom) { + if (this.adapter instanceof LeafletAdapter) + zoom += this.leafletZoomOffset; + this.adapter.setZoom(zoom); + } + addMarker(latLng, options) { + this.adapter.addMarker(latLng, options); + } + destroy() { + this.adapter.destroy(); + } +} + +class WebglDetectionDirective { + platformId = inject(PLATFORM_ID); + webglSupport = output(); + ngOnInit() { + if (!isPlatformBrowser(this.platformId)) + return; + const supported = this.checkWebGLSupport(); + this.webglSupport.emit(supported); + } + checkWebGLSupport() { + let canvas = undefined; + try { + canvas = document.createElement('canvas'); + const gl = (canvas.getContext('webgl') || + canvas.getContext('experimental-webgl')); + const supported = !!window.WebGLRenderingContext && + !!(gl); + return supported; + } + catch { + return false; + } + finally { + canvas?.remove(); + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: WebglDetectionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: WebglDetectionDirective, isStandalone: true, selector: "[webglDetection]", outputs: { webglSupport: "webglSupport" }, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: WebglDetectionDirective, decorators: [{ + type: Directive, + args: [{ + selector: '[webglDetection]', + standalone: true + }] + }] }); + +class OpenMapComponent { + platformId = inject(PLATFORM_ID); + injector = inject(Injector); + webglSupported; + map; + mapContainer; + options = input({ + center: [50.426606229502525, 30.56308375468811], + zoom: 6, + styleUrl: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json', + tileUrl: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', + forceRaster: false, + }); + mapReady = output(); + ngAfterViewInit() { + if (false === isPlatformBrowser(this.platformId)) + return; + runInInjectionContext(this.injector, () => { + effect(() => { + if (undefined === this.webglSupported) + return; + if (!this.map) + this.initializeMap(); + }); + }); + } + webglDetection(supported) { + this.webglSupported = supported; + if (undefined === this.map) + this.initializeMap(); + } + initializeMap() { + const options = this.options(); + this.map = new MapFacade(options.forceRaster, this.webglSupported); + this.map.init(this.mapContainer.nativeElement, options); + this.mapReady.emit(this.map); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: OpenMapComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); + static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.14", type: OpenMapComponent, isStandalone: true, selector: "open-map", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { mapReady: "mapReady" }, viewQueries: [{ propertyName: "mapContainer", first: true, predicate: ["mapContainer"], descendants: true, static: true }], ngImport: i0, template: "
\n\n
\n", styles: [".map-container{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: WebglDetectionDirective, selector: "[webglDetection]", outputs: ["webglSupport"] }] }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: OpenMapComponent, decorators: [{ + type: Component, + args: [{ selector: 'open-map', imports: [ + WebglDetectionDirective + ], standalone: true, template: "
\n\n
\n", styles: [".map-container{width:100%;height:100%}\n"] }] + }], propDecorators: { mapContainer: [{ + type: ViewChild, + args: ['mapContainer', { static: true }] + }] } }); + +/* + * Public API Surface of ngx-open-open-map-wrapper + */ +// Interfaces & types + +/** + * Generated bundle index. Do not edit. + */ + +export { MapFacade, OpenMapComponent, WebglDetectionDirective, getLngLat }; +//# sourceMappingURL=svrnty-ngx-open-map-wrapper.mjs.map diff --git a/fesm2022/svrnty-ngx-open-map-wrapper.mjs.map b/fesm2022/svrnty-ngx-open-map-wrapper.mjs.map new file mode 100644 index 0000000..db74335 --- /dev/null +++ b/fesm2022/svrnty-ngx-open-map-wrapper.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"svrnty-ngx-open-map-wrapper.mjs","sources":["../../../projects/ngx-open-map-wrapper/src/lib/adapters/map-adapter.interface.ts","../../../projects/ngx-open-map-wrapper/src/lib/adapters/libre-adapter.ts","../../../projects/ngx-open-map-wrapper/src/lib/adapters/leaflet-adapter.ts","../../../projects/ngx-open-map-wrapper/src/lib/adapters/map-facade.ts","../../../projects/ngx-open-map-wrapper/src/lib/directives/webgl-detection.directive.ts","../../../projects/ngx-open-map-wrapper/src/lib/components/open-map/open-map.component.ts","../../../projects/ngx-open-map-wrapper/src/lib/components/open-map/open-map.component.html","../../../projects/ngx-open-map-wrapper/src/public-api.ts","../../../projects/ngx-open-map-wrapper/src/svrnty-ngx-open-map-wrapper.ts"],"sourcesContent":["export interface MapOptions {\n center: LatLng;\n zoom: number;\n styleUrl: string;\n tileUrl: string;\n}\n\nexport type LatLng = [number, number];\n\nexport function getLngLat(latLng: LatLng): [number, number] {\n return [latLng[1], latLng[0]];\n}\n\nexport interface IMapAdapter {\n init(container: HTMLElement, options: MapOptions): void;\n setCenter(latLng: LatLng): void;\n setZoom(zoom: number): void;\n addMarker(latLng: LatLng, options?: { color?: string }): void;\n destroy(): void;\n}\n","import { Map, Marker, NavigationControl } from 'maplibre-gl';\nimport {getLngLat, IMapAdapter, LatLng, MapOptions} from './map-adapter.interface';\n\nexport class LibreAdapter implements IMapAdapter {\n private map!: Map;\n\n init(container: HTMLElement, options: MapOptions): void {\n this.map = new Map({\n container,\n style: options.styleUrl!,\n center: getLngLat(options.center),\n zoom: options.zoom,\n });\n\n this.map.addControl(new NavigationControl(), 'top-right');\n }\n\n setCenter(latLng: LatLng): void {\n this.map.setCenter(getLngLat(latLng));\n }\n\n setZoom(zoom: number): void {\n this.map.setZoom(zoom);\n }\n\n addMarker(latLng: LatLng, options?: { color?: string }): void {\n new Marker({ color: options?.color || 'red' })\n .setLngLat(getLngLat(latLng))\n .addTo(this.map);\n }\n\n destroy(): void {\n this.map.remove();\n }\n}\n","import {\n Map,\n TileLayer,\n Marker,\n} from 'leaflet';\n\nimport {\n IMapAdapter,\n LatLng,\n MapOptions,\n} from './map-adapter.interface';\n\nexport class LeafletAdapter implements IMapAdapter {\n private map!: Map;\n\n init(container: HTMLElement, options: MapOptions): void {\n this.map = new Map(container).setView(options.center, options.zoom);\n\n new TileLayer(options.tileUrl, {\n attribution: '© OpenStreetMap contributors',\n }).addTo(this.map);\n }\n\n setCenter(latLng: LatLng): void {\n this.map.setView(latLng, this.map.getZoom());\n }\n\n setZoom(zoom: number): void {\n this.map.setZoom(zoom);\n }\n\n addMarker(latLng: LatLng, options?: { color?: string }): void {\n const marker = new Marker(latLng);\n marker.addTo(this.map);\n }\n\n destroy(): void {\n this.map.remove();\n }\n}\n","import { IMapAdapter, MapOptions, LatLng } from './map-adapter.interface';\nimport { LibreAdapter } from './libre-adapter';\nimport { LeafletAdapter } from './leaflet-adapter';\n\nexport class MapFacade implements IMapAdapter {\n private readonly adapter: IMapAdapter;\n private readonly leafletZoomOffset = 1;\n\n constructor(forceRaster: boolean, webglAvailable: boolean) {\n if (forceRaster || !webglAvailable) {\n this.adapter = new LeafletAdapter();\n } else {\n this.adapter = new LibreAdapter();\n }\n }\n\n init(container: HTMLElement, options: MapOptions): void {\n if (this.adapter instanceof LeafletAdapter)\n options.zoom += this.leafletZoomOffset;\n this.adapter.init(container, options);\n }\n\n setCenter(latLng: LatLng): void {\n this.adapter.setCenter(latLng);\n }\n\n setZoom(zoom: number): void {\n if (this.adapter instanceof LeafletAdapter)\n zoom += this.leafletZoomOffset;\n this.adapter.setZoom(zoom);\n }\n\n addMarker(latLng: LatLng, options?: { color?: string }): void {\n this.adapter.addMarker(latLng, options);\n }\n\n destroy(): void {\n this.adapter.destroy();\n }\n}\n","import {\n Directive,\n inject,\n OnInit, output,\n PLATFORM_ID\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\n@Directive({\n selector: '[webglDetection]',\n standalone: true\n})\nexport class WebglDetectionDirective implements OnInit {\n private readonly platformId = inject(PLATFORM_ID);\n\n webglSupport = output();\n\n ngOnInit(): void {\n if (!isPlatformBrowser(this.platformId))\n return;\n\n const supported = this.checkWebGLSupport();\n this.webglSupport.emit(supported);\n }\n\n private checkWebGLSupport(): boolean {\n let canvas: HTMLCanvasElement | undefined = undefined;\n try {\n canvas = document.createElement('canvas');\n\n const gl = (\n canvas.getContext('webgl') ||\n canvas.getContext('experimental-webgl')\n ) as WebGLRenderingContext | null;\n\n const supported =\n !!window.WebGLRenderingContext &&\n !!(gl);\n\n return supported;\n } catch {\n return false;\n }\n finally {\n canvas?.remove();\n }\n }\n}\n","import {\n AfterViewInit,\n Component,\n effect,\n ElementRef,\n inject, Injector,\n input,\n output,\n PLATFORM_ID, runInInjectionContext,\n ViewChild\n} from '@angular/core';\nimport {isPlatformBrowser} from '@angular/common';\nimport {MapOptions} from '../../adapters/map-adapter.interface';\nimport {MapFacade} from '../../adapters/map-facade';\nimport {WebglDetectionDirective} from '../../directives/webgl-detection.directive';\n\nexport interface OpenMapOptions extends MapOptions {\n forceRaster: boolean;\n}\n\n@Component({\n selector: 'open-map',\n imports: [\n WebglDetectionDirective\n ],\n templateUrl: './open-map.component.html',\n styleUrl: './open-map.component.css',\n standalone: true,\n})\nexport class OpenMapComponent implements AfterViewInit {\n private readonly platformId = inject(PLATFORM_ID);\n private readonly injector = inject(Injector);\n\n webglSupported?: boolean;\n map?: MapFacade;\n\n @ViewChild('mapContainer', { static: true }) mapContainer!: ElementRef;\n\n options = input({\n center: [50.426606229502525, 30.56308375468811],\n zoom: 6,\n styleUrl: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',\n tileUrl: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',\n forceRaster: false,\n });\n\n mapReady = output();\n\n ngAfterViewInit(): void {\n if (false === isPlatformBrowser(this.platformId))\n return;\n\n runInInjectionContext(this.injector, () => {\n effect(() => {\n if (undefined === this.webglSupported)\n return;\n\n if (!this.map)\n this.initializeMap();\n });\n });\n }\n\n webglDetection(supported: boolean): void {\n this.webglSupported = supported;\n if (undefined === this.map)\n this.initializeMap();\n }\n\n private initializeMap(): void {\n const options = this.options();\n this.map = new MapFacade(options.forceRaster, this.webglSupported!);\n this.map.init(this.mapContainer.nativeElement, options);\n this.mapReady.emit(this.map);\n }\n}\n","
\n\n
\n","/*\n * Public API Surface of ngx-open-open-map-wrapper\n */\n\n// Interfaces & types\nexport * from './lib/adapters/map-adapter.interface';\nexport * from './lib/adapters/map-facade';\n\n// Angular components & directives\nexport * from './lib/components/open-map/open-map.component';\nexport * from './lib/directives/webgl-detection.directive';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["Map","Marker"],"mappings":"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"} \ No newline at end of file diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..99bbab3 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,5 @@ +/** + * Generated bundle index. Do not edit. + */ +/// +export * from './public-api'; diff --git a/lib/adapters/leaflet-adapter.d.ts b/lib/adapters/leaflet-adapter.d.ts new file mode 100644 index 0000000..91595ae --- /dev/null +++ b/lib/adapters/leaflet-adapter.d.ts @@ -0,0 +1,11 @@ +import { IMapAdapter, LatLng, MapOptions } from './map-adapter.interface'; +export declare class LeafletAdapter implements IMapAdapter { + private map; + init(container: HTMLElement, options: MapOptions): void; + setCenter(latLng: LatLng): void; + setZoom(zoom: number): void; + addMarker(latLng: LatLng, options?: { + color?: string; + }): void; + destroy(): void; +} diff --git a/lib/adapters/libre-adapter.d.ts b/lib/adapters/libre-adapter.d.ts new file mode 100644 index 0000000..8d1d5e7 --- /dev/null +++ b/lib/adapters/libre-adapter.d.ts @@ -0,0 +1,11 @@ +import { IMapAdapter, LatLng, MapOptions } from './map-adapter.interface'; +export declare class LibreAdapter implements IMapAdapter { + private map; + init(container: HTMLElement, options: MapOptions): void; + setCenter(latLng: LatLng): void; + setZoom(zoom: number): void; + addMarker(latLng: LatLng, options?: { + color?: string; + }): void; + destroy(): void; +} diff --git a/lib/adapters/map-adapter.interface.d.ts b/lib/adapters/map-adapter.interface.d.ts new file mode 100644 index 0000000..14cfaac --- /dev/null +++ b/lib/adapters/map-adapter.interface.d.ts @@ -0,0 +1,17 @@ +export interface MapOptions { + center: LatLng; + zoom: number; + styleUrl: string; + tileUrl: string; +} +export type LatLng = [number, number]; +export declare function getLngLat(latLng: LatLng): [number, number]; +export interface IMapAdapter { + init(container: HTMLElement, options: MapOptions): void; + setCenter(latLng: LatLng): void; + setZoom(zoom: number): void; + addMarker(latLng: LatLng, options?: { + color?: string; + }): void; + destroy(): void; +} diff --git a/lib/adapters/map-facade.d.ts b/lib/adapters/map-facade.d.ts new file mode 100644 index 0000000..3012537 --- /dev/null +++ b/lib/adapters/map-facade.d.ts @@ -0,0 +1,13 @@ +import { IMapAdapter, MapOptions, LatLng } from './map-adapter.interface'; +export declare class MapFacade implements IMapAdapter { + private readonly adapter; + private readonly leafletZoomOffset; + constructor(forceRaster: boolean, webglAvailable: boolean); + init(container: HTMLElement, options: MapOptions): void; + setCenter(latLng: LatLng): void; + setZoom(zoom: number): void; + addMarker(latLng: LatLng, options?: { + color?: string; + }): void; + destroy(): void; +} diff --git a/lib/components/open-map/open-map.component.d.ts b/lib/components/open-map/open-map.component.d.ts new file mode 100644 index 0000000..4c19c19 --- /dev/null +++ b/lib/components/open-map/open-map.component.d.ts @@ -0,0 +1,21 @@ +import { AfterViewInit, ElementRef } from '@angular/core'; +import { MapOptions } from '../../adapters/map-adapter.interface'; +import { MapFacade } from '../../adapters/map-facade'; +import * as i0 from "@angular/core"; +export interface OpenMapOptions extends MapOptions { + forceRaster: boolean; +} +export declare class OpenMapComponent implements AfterViewInit { + private readonly platformId; + private readonly injector; + webglSupported?: boolean; + map?: MapFacade; + mapContainer: ElementRef; + options: import("@angular/core").InputSignal; + mapReady: import("@angular/core").OutputEmitterRef; + ngAfterViewInit(): void; + webglDetection(supported: boolean): void; + private initializeMap; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵcmp: i0.ɵɵComponentDeclaration; +} diff --git a/lib/directives/webgl-detection.directive.d.ts b/lib/directives/webgl-detection.directive.d.ts new file mode 100644 index 0000000..b1b965c --- /dev/null +++ b/lib/directives/webgl-detection.directive.d.ts @@ -0,0 +1,10 @@ +import { OnInit } from '@angular/core'; +import * as i0 from "@angular/core"; +export declare class WebglDetectionDirective implements OnInit { + private readonly platformId; + webglSupport: import("@angular/core").OutputEmitterRef; + ngOnInit(): void; + private checkWebGLSupport; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..741e255 --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "@svrnty/ngx-open-map-wrapper", + "version": "0.2.0", + "keywords": [ + "maplibre", + "leaflet", + "maps", + "open source", + "angular", + "ngx" + ], + "author": "Svrnty", + "license": "MIT", + "publishConfig": { + "access": "public" + }, + "peerDependencies": { + "@angular/common": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "@angular/core": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "maplibre-gl": "^5.0.0", + "leaflet": "^1.0.0 || ^2.0.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false, + "module": "fesm2022/svrnty-ngx-open-map-wrapper.mjs", + "typings": "index.d.ts", + "exports": { + "./package.json": { + "default": "./package.json" + }, + ".": { + "types": "./index.d.ts", + "default": "./fesm2022/svrnty-ngx-open-map-wrapper.mjs" + } + } +} \ No newline at end of file diff --git a/public-api.d.ts b/public-api.d.ts new file mode 100644 index 0000000..e276059 --- /dev/null +++ b/public-api.d.ts @@ -0,0 +1,4 @@ +export * from './lib/adapters/map-adapter.interface'; +export * from './lib/adapters/map-facade'; +export * from './lib/components/open-map/open-map.component'; +export * from './lib/directives/webgl-detection.directive';