map-gl-style-switcher 0.7.0 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,21 +4,23 @@
4
4
  [![CI](https://github.com/muimsd/map-gl-style-switcher/actions/workflows/ci.yml/badge.svg)](https://github.com/muimsd/map-gl-style-switcher/actions/workflows/ci.yml)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![Netlify Status](https://api.netlify.com/api/v1/badges/ea3ee6af-161d-46be-9006-9d31ad52da3c/deploy-status)](https://app.netlify.com/projects/map-gl-style-switcher/deploys)
7
+
7
8
  <!-- [![Coverage Status](https://codecov.io/gh/muimsd/map-gl-style-switcher/branch/main/graph/badge.svg)](https://codecov.io/gh/muimsd/map-gl-style-switcher) -->
8
9
 
9
- A TypeScript control for switching Mapbox GL / MapLibre GL map styles. Easily add a floating style switcher to your map app, with support for multiple styles, images, dark/light themes, and before/after change callbacks.
10
+ A TypeScript control for switching Mapbox GL / MapLibre GL map styles. Easily add a floating style switcher to your map app, with support for multiple styles, images, dark/light themes, and before/after change callbacks.
10
11
 
11
12
  **Available as:**
13
+
12
14
  - `StyleSwitcherControl` - Direct IControl implementation for Mapbox/MapLibre GL
13
15
  - `MapGLStyleSwitcher` - React component for react-map-gl integration
14
16
 
15
- **[🌐 Live Demo](https://map-gl-style-switcher.netlify.app/)**
17
+ **<a href="https://map-gl-style-switcher.netlify.app/" target="_blank">🌐 Live Demo</a>**
16
18
 
17
19
  ## Demo
18
20
 
19
21
  ![Demo GIF](./images/demo.gif)
20
22
 
21
- *Live demo of the style switcher control in action*
23
+ _Live demo of the style switcher control in action_
22
24
 
23
25
  ## Features
24
26
 
@@ -49,6 +51,130 @@ yarn add map-gl-style-switcher
49
51
  pnpm add map-gl-style-switcher
50
52
  ```
51
53
 
54
+ ## CDN Usage
55
+
56
+ For quick prototyping or when you don't want to use a build system, you can include the package directly from a CDN:
57
+
58
+ ### unpkg CDN
59
+
60
+ ```html
61
+ <!DOCTYPE html>
62
+ <html>
63
+ <head>
64
+ <!-- MapLibre GL CSS -->
65
+ <link href="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css" rel="stylesheet" />
66
+
67
+ <!-- Style Switcher CSS -->
68
+ <link rel="stylesheet" href="https://unpkg.com/map-gl-style-switcher@latest/dist/map-gl-style-switcher.css">
69
+ </head>
70
+ <body>
71
+ <div id="map" style="width: 100%; height: 100vh;"></div>
72
+
73
+ <!-- MapLibre GL JS -->
74
+ <script src="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.js"></script>
75
+
76
+ <!-- Style Switcher UMD -->
77
+ <script src="https://unpkg.com/map-gl-style-switcher@latest/dist/index.umd.js"></script>
78
+
79
+ <script>
80
+ // StyleSwitcherControl is available globally as MapGLStyleSwitcher.StyleSwitcherControl
81
+ const { StyleSwitcherControl } = MapGLStyleSwitcher;
82
+
83
+ const styles = [
84
+ {
85
+ id: 'voyager',
86
+ name: 'Voyager',
87
+ image: 'https://unpkg.com/map-gl-style-switcher@latest/public/voyager.png',
88
+ styleUrl: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json',
89
+ description: 'Voyager style from Carto',
90
+ },
91
+ {
92
+ id: 'positron',
93
+ name: 'Positron',
94
+ image: 'https://unpkg.com/map-gl-style-switcher@latest/public/positron.png',
95
+ styleUrl: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
96
+ description: 'Positron style from Carto',
97
+ }
98
+ ];
99
+
100
+ const map = new maplibregl.Map({
101
+ container: 'map',
102
+ style: styles[0].styleUrl,
103
+ center: [0, 0],
104
+ zoom: 2
105
+ });
106
+
107
+ const styleSwitcher = new StyleSwitcherControl({
108
+ styles: styles,
109
+ theme: 'auto',
110
+ activeStyleId: styles[0].id,
111
+ onAfterStyleChange: (from, to) => {
112
+ map.setStyle(to.styleUrl);
113
+ }
114
+ });
115
+
116
+ map.addControl(styleSwitcher, 'bottom-left');
117
+ </script>
118
+ </body>
119
+ </html>
120
+ ```
121
+
122
+ ### jsDelivr CDN
123
+
124
+ ```html
125
+ <!DOCTYPE html>
126
+ <html>
127
+ <head>
128
+ <!-- MapLibre GL CSS -->
129
+ <link href="https://cdn.jsdelivr.net/npm/maplibre-gl@4/dist/maplibre-gl.css" rel="stylesheet" />
130
+
131
+ <!-- Style Switcher CSS -->
132
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/map-gl-style-switcher@latest/dist/map-gl-style-switcher.css">
133
+ </head>
134
+ <body>
135
+ <div id="map" style="width: 100%; height: 100vh;"></div>
136
+
137
+ <!-- MapLibre GL JS -->
138
+ <script src="https://cdn.jsdelivr.net/npm/maplibre-gl@4/dist/maplibre-gl.js"></script>
139
+
140
+ <!-- Style Switcher UMD -->
141
+ <script src="https://cdn.jsdelivr.net/npm/map-gl-style-switcher@latest/dist/index.umd.js"></script>
142
+
143
+ <script>
144
+ // Same JavaScript code as above
145
+ const { StyleSwitcherControl } = MapGLStyleSwitcher;
146
+ // ... rest of the code
147
+ </script>
148
+ </body>
149
+ </html>
150
+ ```
151
+
152
+ ### ES Modules from CDN
153
+
154
+ For modern browsers that support ES modules:
155
+
156
+ ```html
157
+ <script type="module">
158
+ import { StyleSwitcherControl } from 'https://unpkg.com/map-gl-style-switcher@latest/dist/index.js';
159
+
160
+ // Your code here
161
+ const styleSwitcher = new StyleSwitcherControl({
162
+ styles: styles,
163
+ theme: 'auto'
164
+ });
165
+ </script>
166
+ ```
167
+
168
+ ### Specific Version
169
+
170
+ To use a specific version instead of `@latest`:
171
+
172
+ ```html
173
+ <!-- Replace @latest with specific version, e.g., @0.7.2 -->
174
+ <link rel="stylesheet" href="https://unpkg.com/map-gl-style-switcher@0.7.2/dist/map-gl-style-switcher.css">
175
+ <script src="https://unpkg.com/map-gl-style-switcher@0.7.2/dist/index.umd.js"></script>
176
+ ```
177
+
52
178
  ## Usage
53
179
 
54
180
  ### Basic MapLibre GL Integration
@@ -85,14 +211,16 @@ const styles = [
85
211
  id: 'arcgis-hybrid',
86
212
  name: 'ArcGIS Hybrid',
87
213
  image: './arcgis-hybrid.png',
88
- styleUrl: 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/arcgis_hybrid.json',
214
+ styleUrl:
215
+ 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/arcgis_hybrid.json',
89
216
  description: 'Hybrid Satellite style from ESRI',
90
217
  },
91
218
  {
92
219
  id: 'osm',
93
220
  name: 'OSM',
94
221
  image: './osm.png',
95
- styleUrl: 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/openStreetMap.json',
222
+ styleUrl:
223
+ 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/openStreetMap.json',
96
224
  description: 'OSM style',
97
225
  },
98
226
  ];
@@ -125,11 +253,7 @@ map.addControl(styleSwitcher, 'bottom-left');
125
253
 
126
254
  ### React Integration with react-map-gl
127
255
 
128
- For React applications using `react-map-gl`, you have two options:
129
-
130
- #### Using the Built-in MapGLStyleSwitcher Component (Recommended)
131
-
132
- This package provides a ready-to-use `MapGLStyleSwitcher` component:
256
+ For React applications using `react-map-gl`, This package provides a ready-to-use `MapGLStyleSwitcher` component:
133
257
 
134
258
  ```tsx
135
259
  import React, { useState } from 'react';
@@ -163,14 +287,16 @@ const styles = [
163
287
  id: 'arcgis-hybrid',
164
288
  name: 'ArcGIS Hybrid',
165
289
  image: './arcgis-hybrid.png',
166
- styleUrl: 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/arcgis_hybrid.json',
290
+ styleUrl:
291
+ 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/arcgis_hybrid.json',
167
292
  description: 'Hybrid Satellite style from ESRI',
168
293
  },
169
294
  {
170
295
  id: 'osm',
171
296
  name: 'OSM',
172
297
  image: './osm.png',
173
- styleUrl: 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/openStreetMap.json',
298
+ styleUrl:
299
+ 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/openStreetMap.json',
174
300
  description: 'OSM style',
175
301
  },
176
302
  ];
@@ -184,7 +310,7 @@ export const MapComponent = () => {
184
310
  initialViewState={{
185
311
  longitude: 0,
186
312
  latitude: 0,
187
- zoom: 2
313
+ zoom: 2,
188
314
  }}
189
315
  style={{ width: '100%', height: '100vh' }}
190
316
  mapStyle={mapStyle}
@@ -213,17 +339,21 @@ npm install react-map-gl maplibre-gl map-gl-style-switcher
213
339
 
214
340
  ```tsx
215
341
  interface MapGLStyleSwitcherProps {
216
- styles: StyleItem[]; // Array of map styles (required)
217
- activeStyleId?: string; // Currently active style ID
218
- theme?: 'light' | 'dark' | 'auto'; // UI theme (default: 'light')
219
- showLabels?: boolean; // Show style names (default: true)
220
- showImages?: boolean; // Show style thumbnails (default: true)
221
- position?: 'top-left' | 'top-right' | // Control position (default: 'bottom-left')
222
- 'bottom-left' | 'bottom-right';
223
- animationDuration?: number; // Animation duration in ms (default: 200)
224
- maxHeight?: number; // Max height of expanded list (default: 300)
225
- rtl?: boolean; // Enable RTL layout (default: false)
226
- classNames?: Partial<{ // Custom CSS classes
342
+ styles: StyleItem[]; // Array of map styles (required)
343
+ activeStyleId?: string; // Currently active style ID
344
+ theme?: 'light' | 'dark' | 'auto'; // UI theme (default: 'light')
345
+ showLabels?: boolean; // Show style names (default: true)
346
+ showImages?: boolean; // Show style thumbnails (default: true)
347
+ position?:
348
+ | 'top-left'
349
+ | 'top-right' // Control position (default: 'bottom-left')
350
+ | 'bottom-left'
351
+ | 'bottom-right';
352
+ animationDuration?: number; // Animation duration in ms (default: 200)
353
+ maxHeight?: number; // Max height of expanded list (default: 300)
354
+ rtl?: boolean; // Enable RTL layout (default: false)
355
+ classNames?: Partial<{
356
+ // Custom CSS classes
227
357
  container: string;
228
358
  list: string;
229
359
  item: string;
@@ -232,9 +362,9 @@ interface MapGLStyleSwitcherProps {
232
362
  dark: string;
233
363
  light: string;
234
364
  }>;
235
- onBeforeStyleChange?: (from: StyleItem, to: StyleItem) => void; // Callback before style change
236
- onAfterStyleChange?: (from: StyleItem, to: StyleItem) => void; // Callback after style change
237
- onStyleChange?: (styleUrl: string) => void; // Simplified callback for style URL
365
+ onBeforeStyleChange?: (from: StyleItem, to: StyleItem) => void; // Callback before style change
366
+ onAfterStyleChange?: (from: StyleItem, to: StyleItem) => void; // Callback after style change
367
+ onStyleChange?: (styleUrl: string) => void; // Simplified callback for style URL
238
368
  }
239
369
  ```
240
370
 
@@ -291,8 +421,9 @@ npm run dev
291
421
  ```
292
422
 
293
423
  This example demonstrates:
424
+
294
425
  - React 19 with TypeScript and Vite 7
295
- - MapLibre GL integration with react-map-gl
426
+ - MapLibre GL integration with react-map-gl
296
427
  - MapGLStyleSwitcher component usage
297
428
  - Multiple basemap styles with thumbnails
298
429
  - Responsive design with auto theme detection
@@ -310,10 +441,12 @@ npm run dev
310
441
  ```
311
442
 
312
443
  This example shows:
444
+
313
445
  - Pure TypeScript/JavaScript implementation
314
446
  - MapLibre GL integration
315
447
  - StyleSwitcherControl direct usage
316
448
  - Multiple themes and configuration options
449
+
317
450
  ## Available Styles
318
451
 
319
452
  ![Available Styles](./images/styles.png)
@@ -321,15 +454,18 @@ This example shows:
321
454
  The style switcher supports various map styles. Here are some popular options you can use:
322
455
 
323
456
  ### Carto Basemaps
457
+
324
458
  - **Voyager** - A balanced, colorful style perfect for data visualization and general mapping applications
325
459
  - **Positron** - A clean, minimal light basemap ideal for overlaying data with maximum contrast
326
460
  - **Dark Matter** - A dark theme basemap excellent for creating striking data visualizations and night mode interfaces
327
461
 
328
462
  ### Satellite & Hybrid
463
+
329
464
  - **ArcGIS Hybrid** - Combines satellite imagery with street labels, perfect for geographic context and navigation
330
465
  - **Satellite** - High-resolution satellite imagery for detailed geographic analysis
331
466
 
332
467
  ### OpenStreetMap
468
+
333
469
  - **OSM (OpenStreetMap)** - Community-driven open-source mapping with detailed street-level information
334
470
 
335
471
  ### Example Styles Configuration
@@ -345,7 +481,7 @@ const styles = [
345
481
  },
346
482
  {
347
483
  id: 'positron',
348
- name: 'Positron',
484
+ name: 'Positron',
349
485
  image: './positron.png',
350
486
  styleUrl: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
351
487
  description: 'Positron style from Carto',
@@ -361,14 +497,16 @@ const styles = [
361
497
  id: 'arcgis-hybrid',
362
498
  name: 'ArcGIS Hybrid',
363
499
  image: './arcgis-hybrid.png',
364
- styleUrl: 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/arcgis_hybrid.json',
500
+ styleUrl:
501
+ 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/arcgis_hybrid.json',
365
502
  description: 'Hybrid Satellite style from ESRI',
366
503
  },
367
504
  {
368
505
  id: 'osm',
369
506
  name: 'OSM',
370
507
  image: './osm.png',
371
- styleUrl: 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/openStreetMap.json',
508
+ styleUrl:
509
+ 'https://raw.githubusercontent.com/go2garret/maps/main/src/assets/json/openStreetMap.json',
372
510
  description: 'OSM style',
373
511
  },
374
512
  ];
@@ -412,7 +550,7 @@ interface StyleSwitcherClassNames {
412
550
  }
413
551
  ```
414
552
 
415
- *Example of different map styles that can be used with the style switcher*
553
+ _Example of different map styles that can be used with the style switcher_
416
554
 
417
555
  ### Option Details
418
556
 
@@ -569,7 +707,6 @@ We welcome contributions! Please feel free to submit a Pull Request. For major c
569
707
  ```
570
708
 
571
709
  4. **Make your changes**
572
-
573
710
  - Follow TypeScript best practices
574
711
  - Maintain backward compatibility when possible
575
712
  - Add tests for new features
@@ -1 +1,195 @@
1
- .maplibregl-ctrl.style-switcher,.mapboxgl-ctrl.style-switcher{box-shadow:0 2px 4px rgba(0,0,0,0.15);background:#fff;border-radius:6px;padding:4px;margin:8px;transition:box-shadow 0.2s;min-width:unset;width:auto;user-select:none;cursor:pointer;}[dir='rtl'] .maplibregl-ctrl.style-switcher,[dir='rtl'] .mapboxgl-ctrl.style-switcher,.maplibregl-ctrl.style-switcher[dir='rtl'],.mapboxgl-ctrl.style-switcher[dir='rtl']{direction:rtl;}.maplibregl-ctrl.style-switcher.style-switcher-dark,.mapboxgl-ctrl.style-switcher.style-switcher-dark{background:#2a2a2a;color:#fff;border:1px solid #444;}.maplibregl-ctrl.style-switcher.style-switcher-light,.mapboxgl-ctrl.style-switcher.style-switcher-light{background:#ffffff;color:#333;border:1px solid #ddd;}.style-switcher-list{display:flex;flex-direction:column;gap:4px;padding:4px 0px;max-height:300px;overflow-y:auto;overflow-x:hidden;}[dir='rtl'] .style-switcher-list,.style-switcher-list[dir='rtl']{direction:rtl;}.style-switcher-item{display:flex;align-items:center;gap:6px;cursor:pointer;padding:2px 4px;border-radius:4px;transition:all 0.2s ease;border:2px solid transparent;position:relative;overflow:hidden;}.style-switcher-item:hover{background:#f0f8ff;transform:translateY(-1px);}.style-switcher-item.selected{background:#e6f0ff;font-weight:600;border:1px solid #0066cc;}.style-switcher-item:not(:has(span)){min-width:unset;width:40px;justify-content:center;padding-left:0;padding-right:0;}.style-switcher-item.hide-label span{display:none !important;}.maplibregl-ctrl.style-switcher.style-switcher-dark .style-switcher-item:hover,.mapboxgl-ctrl.style-switcher.style-switcher-dark .style-switcher-item:hover{background:#333;}.maplibregl-ctrl.style-switcher.style-switcher-dark .style-switcher-item.selected,.mapboxgl-ctrl.style-switcher.style-switcher-dark .style-switcher-item.selected{background:#404040;border-color:#666;}.style-switcher-item img{width:32px;height:32px;object-fit:cover;border-radius:2px;background:#f0f0f0;border:1px solid #ddd;flex-shrink:0;transition:all 0.2s ease;}.maplibregl-ctrl.style-switcher.style-switcher-dark .style-switcher-item img,.mapboxgl-ctrl.style-switcher.style-switcher-dark .style-switcher-item img{background:#555;border-color:#666;}.style-switcher-item span{font-size:14px;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0;}.maplibregl-ctrl.style-switcher:focus,.mapboxgl-ctrl.style-switcher:focus{outline:2px solid #0066cc;outline-offset:1px;}.style-switcher-item:focus{outline:2px solid #0066cc;outline-offset:1px;}.style-switcher-list{animation:fadeIn 0.2s ease-in-out;}@keyframes fadeIn{from{opacity:0;transform:translateY(-10px);}to{opacity:1;transform:translateY(0);}}.style-switcher-list::-webkit-scrollbar{width:4px;}.style-switcher-list::-webkit-scrollbar-track{background:#f0f0f0;border-radius:2px;}.style-switcher-list::-webkit-scrollbar-thumb{background:#ccc;border-radius:2px;}.maplibregl-ctrl.style-switcher.style-switcher-dark .style-switcher-list::-webkit-scrollbar-track,.mapboxgl-ctrl.style-switcher.style-switcher-dark .style-switcher-list::-webkit-scrollbar-track{background:#2a2a2a;}.maplibregl-ctrl.style-switcher.style-switcher-dark .style-switcher-list::-webkit-scrollbar-thumb,.mapboxgl-ctrl.style-switcher.style-switcher-dark .style-switcher-list::-webkit-scrollbar-thumb{background:#555;}
1
+ /* Override MapLibre GL and Mapbox GL control styles for style switcher */
2
+ .maplibregl-ctrl.style-switcher,
3
+ .mapboxgl-ctrl.style-switcher {
4
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
5
+ background: #fff;
6
+ border-radius: 6px;
7
+ padding: 4px;
8
+ margin: 8px;
9
+ transition: box-shadow 0.2s;
10
+ min-width: unset;
11
+ width: auto;
12
+ user-select: none;
13
+ cursor: pointer;
14
+ }
15
+
16
+ /* RTL support */
17
+ [dir='rtl'] .maplibregl-ctrl.style-switcher,
18
+ [dir='rtl'] .mapboxgl-ctrl.style-switcher,
19
+ .maplibregl-ctrl.style-switcher[dir='rtl'],
20
+ .mapboxgl-ctrl.style-switcher[dir='rtl'] {
21
+ direction: rtl;
22
+ }
23
+
24
+ /* Theme variants */
25
+ .maplibregl-ctrl.style-switcher.style-switcher-dark,
26
+ .mapboxgl-ctrl.style-switcher.style-switcher-dark {
27
+ background: #2a2a2a;
28
+ color: #fff;
29
+ border: 1px solid #444;
30
+ }
31
+
32
+ .maplibregl-ctrl.style-switcher.style-switcher-light,
33
+ .mapboxgl-ctrl.style-switcher.style-switcher-light {
34
+ background: #ffffff;
35
+ color: #333;
36
+ border: 1px solid #ddd;
37
+ }
38
+
39
+ /* List container */
40
+ .style-switcher-list {
41
+ display: flex;
42
+ flex-direction: column;
43
+ gap: 4px;
44
+ padding: 4px 0px;
45
+ max-height: 300px;
46
+ overflow-y: auto;
47
+ overflow-x: hidden;
48
+ }
49
+
50
+ /* RTL support for list */
51
+ [dir='rtl'] .style-switcher-list,
52
+ .style-switcher-list[dir='rtl'] {
53
+ direction: rtl;
54
+ }
55
+
56
+ /* Individual style items */
57
+ .style-switcher-item {
58
+ display: flex;
59
+ align-items: center;
60
+ gap: 6px;
61
+ cursor: pointer;
62
+ padding: 2px 4px;
63
+ border-radius: 4px;
64
+ transition: all 0.2s ease;
65
+ border: 2px solid transparent;
66
+ position: relative;
67
+ overflow: hidden;
68
+ }
69
+
70
+ .style-switcher-item:hover {
71
+ background: #f0f8ff;
72
+ transform: translateY(-1px);
73
+ }
74
+
75
+ .style-switcher-item.selected {
76
+ background: #e6f0ff;
77
+ font-weight: 600;
78
+ border: 1px solid #0066cc;
79
+ }
80
+
81
+ /* When labels are hidden, shrink items to image size only */
82
+ .style-switcher-item:not(:has(span)) {
83
+ min-width: unset;
84
+ width: 40px;
85
+ justify-content: center;
86
+ padding-left: 0;
87
+ padding-right: 0;
88
+ }
89
+
90
+ /* Hide label span if showLabels is false (for safety) */
91
+ .style-switcher-item.hide-label span {
92
+ display: none !important;
93
+ }
94
+
95
+ /* Dark theme item styles */
96
+ .maplibregl-ctrl.style-switcher.style-switcher-dark .style-switcher-item:hover,
97
+ .mapboxgl-ctrl.style-switcher.style-switcher-dark .style-switcher-item:hover {
98
+ background: #333;
99
+ }
100
+
101
+ .maplibregl-ctrl.style-switcher.style-switcher-dark
102
+ .style-switcher-item.selected,
103
+ .mapboxgl-ctrl.style-switcher.style-switcher-dark
104
+ .style-switcher-item.selected {
105
+ background: #404040;
106
+ border-color: #666;
107
+ }
108
+
109
+ /* Image styles */
110
+ .style-switcher-item img {
111
+ width: 32px;
112
+ height: 32px;
113
+ object-fit: cover;
114
+ border-radius: 2px;
115
+ background: #f0f0f0;
116
+ border: 1px solid #ddd;
117
+ flex-shrink: 0;
118
+ transition: all 0.2s ease;
119
+ }
120
+
121
+ /* Image styles - dark theme */
122
+ .maplibregl-ctrl.style-switcher.style-switcher-dark .style-switcher-item img,
123
+ .mapboxgl-ctrl.style-switcher.style-switcher-dark .style-switcher-item img {
124
+ background: #555;
125
+ border-color: #666;
126
+ }
127
+
128
+ /* Text styles */
129
+ .style-switcher-item span {
130
+ font-size: 14px;
131
+ line-height: 1.2;
132
+ white-space: nowrap;
133
+ overflow: hidden;
134
+ text-overflow: ellipsis;
135
+ flex: 1;
136
+ min-width: 0;
137
+ }
138
+
139
+ /* Accessibility improvements */
140
+ .maplibregl-ctrl.style-switcher:focus,
141
+ .mapboxgl-ctrl.style-switcher:focus {
142
+ outline: 2px solid #0066cc;
143
+ outline-offset: 1px;
144
+ }
145
+
146
+ .style-switcher-item:focus {
147
+ outline: 2px solid #0066cc;
148
+ outline-offset: 1px;
149
+ }
150
+
151
+ /* Animation for expand/collapse */
152
+ .style-switcher-list {
153
+ animation: fadeIn 0.2s ease-in-out;
154
+ }
155
+
156
+ @keyframes fadeIn {
157
+ from {
158
+ opacity: 0;
159
+ transform: translateY(-10px);
160
+ }
161
+ to {
162
+ opacity: 1;
163
+ transform: translateY(0);
164
+ }
165
+ }
166
+
167
+ /* Scrollbar styling */
168
+ .style-switcher-list::-webkit-scrollbar {
169
+ width: 4px;
170
+ }
171
+
172
+ .style-switcher-list::-webkit-scrollbar-track {
173
+ background: #f0f0f0;
174
+ border-radius: 2px;
175
+ }
176
+
177
+ .style-switcher-list::-webkit-scrollbar-thumb {
178
+ background: #ccc;
179
+ border-radius: 2px;
180
+ }
181
+
182
+ /* Scrollbar styling - dark theme */
183
+ .maplibregl-ctrl.style-switcher.style-switcher-dark
184
+ .style-switcher-list::-webkit-scrollbar-track,
185
+ .mapboxgl-ctrl.style-switcher.style-switcher-dark
186
+ .style-switcher-list::-webkit-scrollbar-track {
187
+ background: #2a2a2a;
188
+ }
189
+
190
+ .maplibregl-ctrl.style-switcher.style-switcher-dark
191
+ .style-switcher-list::-webkit-scrollbar-thumb,
192
+ .mapboxgl-ctrl.style-switcher.style-switcher-dark
193
+ .style-switcher-list::-webkit-scrollbar-thumb {
194
+ background: #555;
195
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "map-gl-style-switcher",
3
- "version": "0.7.0",
3
+ "version": "0.7.5",
4
4
  "description": "A customizable style switcher control for Mapbox GL JS and MapLibre GL JS",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",