@djangocfg/ui-tools 2.1.110 → 2.1.112
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 +242 -49
- package/dist/JsonSchemaForm-65NLLK56.mjs +4 -0
- package/dist/JsonSchemaForm-65NLLK56.mjs.map +1 -0
- package/dist/JsonSchemaForm-PY6DH3HE.cjs +13 -0
- package/dist/JsonSchemaForm-PY6DH3HE.cjs.map +1 -0
- package/dist/JsonTree-6RYAOPSS.mjs +4 -0
- package/dist/JsonTree-6RYAOPSS.mjs.map +1 -0
- package/dist/JsonTree-7OH6CIHT.cjs +10 -0
- package/dist/JsonTree-7OH6CIHT.cjs.map +1 -0
- package/dist/MapContainer-GXQLP5WY.mjs +214 -0
- package/dist/MapContainer-GXQLP5WY.mjs.map +1 -0
- package/dist/MapContainer-RYG4HPH4.cjs +221 -0
- package/dist/MapContainer-RYG4HPH4.cjs.map +1 -0
- package/dist/{Mermaid.client-4OCKJ6QD.mjs → Mermaid.client-OKACITCW.mjs} +16 -7
- package/dist/Mermaid.client-OKACITCW.mjs.map +1 -0
- package/dist/{Mermaid.client-ZP6OE46Z.cjs → Mermaid.client-PNXEC6YL.cjs} +16 -7
- package/dist/Mermaid.client-PNXEC6YL.cjs.map +1 -0
- package/dist/{PlaygroundLayout-XXVBU4WZ.cjs → PlaygroundLayout-SYMEAG3J.cjs} +25 -24
- package/dist/PlaygroundLayout-SYMEAG3J.cjs.map +1 -0
- package/dist/{PlaygroundLayout-LMQTVXSP.mjs → PlaygroundLayout-UQRBU5RH.mjs} +4 -3
- package/dist/PlaygroundLayout-UQRBU5RH.mjs.map +1 -0
- package/dist/{PrettyCode.client-2CLSV2VD.cjs → PrettyCode.client-DANYYQYO.cjs} +11 -4
- package/dist/PrettyCode.client-DANYYQYO.cjs.map +1 -0
- package/dist/{PrettyCode.client-Y2BVON7R.mjs → PrettyCode.client-RS5ZTNBT.mjs} +11 -4
- package/dist/PrettyCode.client-RS5ZTNBT.mjs.map +1 -0
- package/dist/chunk-2DSR7V2L.mjs +561 -0
- package/dist/chunk-2DSR7V2L.mjs.map +1 -0
- package/dist/chunk-47T5ECYV.cjs +1357 -0
- package/dist/chunk-47T5ECYV.cjs.map +1 -0
- package/dist/chunk-5QT3QYFZ.cjs +189 -0
- package/dist/chunk-5QT3QYFZ.cjs.map +1 -0
- package/dist/chunk-7IIRYG4S.mjs +1057 -0
- package/dist/chunk-7IIRYG4S.mjs.map +1 -0
- package/dist/{chunk-FB5QBSI3.cjs → chunk-DI3HUXHK.cjs} +15 -195
- package/dist/chunk-DI3HUXHK.cjs.map +1 -0
- package/dist/chunk-EVGWYASL.cjs +1528 -0
- package/dist/chunk-EVGWYASL.cjs.map +1 -0
- package/dist/chunk-F2N7P5XU.cjs +30 -0
- package/dist/chunk-F2N7P5XU.cjs.map +1 -0
- package/dist/{chunk-L6UHASYQ.mjs → chunk-G6PRZP5I.mjs} +7 -186
- package/dist/chunk-G6PRZP5I.mjs.map +1 -0
- package/dist/chunk-JWB2EWQO.mjs +5 -0
- package/dist/chunk-JWB2EWQO.mjs.map +1 -0
- package/dist/chunk-LTJX2JXE.mjs +338 -0
- package/dist/chunk-LTJX2JXE.mjs.map +1 -0
- package/dist/chunk-OVNC4KW6.mjs +1494 -0
- package/dist/chunk-OVNC4KW6.mjs.map +1 -0
- package/dist/chunk-PNZSJN6T.cjs +1086 -0
- package/dist/chunk-PNZSJN6T.cjs.map +1 -0
- package/dist/chunk-TEFRA7GW.cjs +565 -0
- package/dist/chunk-TEFRA7GW.cjs.map +1 -0
- package/dist/chunk-UOMPPIED.mjs +1343 -0
- package/dist/chunk-UOMPPIED.mjs.map +1 -0
- package/dist/chunk-W6YHQI4F.mjs +187 -0
- package/dist/chunk-W6YHQI4F.mjs.map +1 -0
- package/dist/chunk-XTBRWVIV.cjs +346 -0
- package/dist/chunk-XTBRWVIV.cjs.map +1 -0
- package/dist/components-C7ZL7OMY.mjs +5 -0
- package/dist/components-C7ZL7OMY.mjs.map +1 -0
- package/dist/components-CJ2IB65O.cjs +27 -0
- package/dist/components-CJ2IB65O.cjs.map +1 -0
- package/dist/components-EASJYK45.mjs +6 -0
- package/dist/components-EASJYK45.mjs.map +1 -0
- package/dist/components-LDRFDV4A.cjs +22 -0
- package/dist/components-LDRFDV4A.cjs.map +1 -0
- package/dist/components-VZKUTDJK.mjs +5 -0
- package/dist/components-VZKUTDJK.mjs.map +1 -0
- package/dist/components-Y64GTIMQ.cjs +42 -0
- package/dist/components-Y64GTIMQ.cjs.map +1 -0
- package/dist/index.cjs +701 -4813
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1274 -1026
- package/dist/index.d.ts +1274 -1026
- package/dist/index.mjs +358 -4730
- package/dist/index.mjs.map +1 -1
- package/package.json +27 -4
- package/src/components/index.ts +17 -0
- package/src/components/lazy-wrapper.tsx +281 -0
- package/src/index.ts +92 -7
- package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +14 -5
- package/src/tools/AudioPlayer/lazy.tsx +85 -0
- package/src/tools/Gallery/components/Gallery.tsx +182 -0
- package/src/tools/Gallery/components/GalleryCarousel.tsx +251 -0
- package/src/tools/Gallery/components/GalleryCompact.tsx +173 -0
- package/src/tools/Gallery/components/GalleryGrid.tsx +493 -0
- package/src/tools/Gallery/components/GalleryImage.tsx +66 -0
- package/src/tools/Gallery/components/GalleryLightbox.tsx +331 -0
- package/src/tools/Gallery/components/GalleryMedia.tsx +66 -0
- package/src/tools/Gallery/components/GalleryThumbnails.tsx +173 -0
- package/src/tools/Gallery/components/GalleryThumbnailsVirtual.tsx +138 -0
- package/src/tools/Gallery/components/GalleryVideo.tsx +222 -0
- package/src/tools/Gallery/components/index.ts +13 -0
- package/src/tools/Gallery/hooks/index.ts +23 -0
- package/src/tools/Gallery/hooks/useGallery.ts +137 -0
- package/src/tools/Gallery/hooks/useImageDimensions.ts +223 -0
- package/src/tools/Gallery/hooks/usePinchZoom.ts +234 -0
- package/src/tools/Gallery/hooks/usePreloadImages.ts +71 -0
- package/src/tools/Gallery/hooks/useSwipe.ts +86 -0
- package/src/tools/Gallery/hooks/useVirtualList.ts +129 -0
- package/src/tools/Gallery/hooks/useZoom.ts +316 -0
- package/src/tools/Gallery/index.ts +66 -0
- package/src/tools/Gallery/types.ts +183 -0
- package/src/tools/Gallery/utils/imageAnalysis.ts +52 -0
- package/src/tools/Gallery/utils/index.ts +11 -0
- package/src/tools/ImageViewer/components/ImageToolbar.tsx +20 -8
- package/src/tools/ImageViewer/components/ImageViewer.tsx +12 -4
- package/src/tools/ImageViewer/lazy.tsx +37 -0
- package/src/tools/JsonForm/lazy.tsx +43 -0
- package/src/tools/JsonForm/widgets/ColorWidget.tsx +4 -1
- package/src/tools/JsonTree/lazy.tsx +45 -0
- package/src/tools/LottiePlayer/lazy.tsx +57 -0
- package/src/tools/Map/components/CustomOverlay.tsx +54 -0
- package/src/tools/Map/components/DrawControl.tsx +36 -0
- package/src/tools/Map/components/GeocoderControl.tsx +70 -0
- package/src/tools/Map/components/LayerSwitcher.tsx +225 -0
- package/src/tools/Map/components/MapCluster.tsx +273 -0
- package/src/tools/Map/components/MapContainer.tsx +191 -0
- package/src/tools/Map/components/MapControls.tsx +44 -0
- package/src/tools/Map/components/MapLegend.tsx +161 -0
- package/src/tools/Map/components/MapMarker.tsx +102 -0
- package/src/tools/Map/components/MapPopup.tsx +46 -0
- package/src/tools/Map/components/MapSource.tsx +30 -0
- package/src/tools/Map/components/index.ts +20 -0
- package/src/tools/Map/context/MapContext.tsx +89 -0
- package/src/tools/Map/context/index.ts +2 -0
- package/src/tools/Map/hooks/index.ts +9 -0
- package/src/tools/Map/hooks/useMap.ts +11 -0
- package/src/tools/Map/hooks/useMapControl.ts +99 -0
- package/src/tools/Map/hooks/useMapEvents.ts +147 -0
- package/src/tools/Map/hooks/useMapLayers.ts +83 -0
- package/src/tools/Map/hooks/useMapViewport.ts +62 -0
- package/src/tools/Map/hooks/useMarkers.ts +85 -0
- package/src/tools/Map/index.ts +116 -0
- package/src/tools/Map/layers/cluster.ts +94 -0
- package/src/tools/Map/layers/index.ts +15 -0
- package/src/tools/Map/layers/line.ts +93 -0
- package/src/tools/Map/layers/point.ts +61 -0
- package/src/tools/Map/layers/polygon.ts +73 -0
- package/src/tools/Map/lazy.tsx +56 -0
- package/src/tools/Map/styles/index.ts +15 -0
- package/src/tools/Map/types.ts +259 -0
- package/src/tools/Map/utils/geo.ts +88 -0
- package/src/tools/Map/utils/index.ts +16 -0
- package/src/tools/Map/utils/transform.ts +107 -0
- package/src/tools/Mermaid/Mermaid.client.tsx +12 -4
- package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +6 -2
- package/src/tools/Mermaid/lazy.tsx +46 -0
- package/src/tools/OpenapiViewer/lazy.tsx +72 -0
- package/src/tools/PrettyCode/PrettyCode.client.tsx +10 -3
- package/src/tools/PrettyCode/lazy.tsx +64 -0
- package/src/tools/VideoPlayer/lazy.tsx +63 -0
- package/dist/Mermaid.client-4OCKJ6QD.mjs.map +0 -1
- package/dist/Mermaid.client-ZP6OE46Z.cjs.map +0 -1
- package/dist/PlaygroundLayout-LMQTVXSP.mjs.map +0 -1
- package/dist/PlaygroundLayout-XXVBU4WZ.cjs.map +0 -1
- package/dist/PrettyCode.client-2CLSV2VD.cjs.map +0 -1
- package/dist/PrettyCode.client-Y2BVON7R.mjs.map +0 -1
- package/dist/chunk-FB5QBSI3.cjs.map +0 -1
- package/dist/chunk-L6UHASYQ.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -6,8 +6,6 @@ Heavy React tools with lazy loading (React.lazy + Suspense).
|
|
|
6
6
|
|
|
7
7
|
**Part of [DjangoCFG](https://djangocfg.com)** — modern Django framework for production-ready SaaS applications.
|
|
8
8
|
|
|
9
|
-
**[Live Demo & Props](https://djangocfg.com/demo/)**
|
|
10
|
-
|
|
11
9
|
## Install
|
|
12
10
|
|
|
13
11
|
```bash
|
|
@@ -20,14 +18,16 @@ This package contains heavy components that are loaded lazily to keep your initi
|
|
|
20
18
|
|
|
21
19
|
| Package | Use Case |
|
|
22
20
|
|---------|----------|
|
|
23
|
-
| `@djangocfg/ui-core` | Lightweight UI components (60 components) |
|
|
21
|
+
| `@djangocfg/ui-core` | Lightweight UI components (60+ components) |
|
|
24
22
|
| `@djangocfg/ui-tools` | Heavy tools with lazy loading |
|
|
25
23
|
| `@djangocfg/ui-nextjs` | Next.js apps (extends ui-core) |
|
|
26
24
|
|
|
27
|
-
## Tools (
|
|
25
|
+
## Tools (11)
|
|
28
26
|
|
|
29
27
|
| Tool | Bundle Size | Description |
|
|
30
28
|
|------|-------------|-------------|
|
|
29
|
+
| `Gallery` | ~50KB | Image/video gallery with carousel, grid, lightbox |
|
|
30
|
+
| `Map` | ~800KB | MapLibre GL maps with markers, clusters, layers |
|
|
31
31
|
| `Mermaid` | ~800KB | Diagram rendering |
|
|
32
32
|
| `PrettyCode` | ~500KB | Code syntax highlighting |
|
|
33
33
|
| `OpenapiViewer` | ~400KB | OpenAPI schema viewer & playground |
|
|
@@ -38,40 +38,189 @@ This package contains heavy components that are loaded lazily to keep your initi
|
|
|
38
38
|
| `JsonTree` | ~100KB | JSON visualization |
|
|
39
39
|
| `ImageViewer` | ~50KB | Image viewer with zoom/pan/rotate |
|
|
40
40
|
|
|
41
|
-
##
|
|
41
|
+
## Tree-Shakeable Imports
|
|
42
|
+
|
|
43
|
+
For better bundle optimization, use subpath imports:
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
// Only loads Gallery (~50KB instead of full package)
|
|
47
|
+
import { Gallery, GalleryLightbox } from '@djangocfg/ui-tools/gallery';
|
|
48
|
+
|
|
49
|
+
// Only loads Map (~800KB)
|
|
50
|
+
import { MapContainer, MapMarker } from '@djangocfg/ui-tools/map';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Gallery
|
|
54
|
+
|
|
55
|
+
Full-featured image/video gallery with carousel, grid view, and fullscreen lightbox.
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { Gallery } from '@djangocfg/ui-tools/gallery';
|
|
59
|
+
|
|
60
|
+
const images = [
|
|
61
|
+
{ id: '1', src: '/photo1.jpg', alt: 'Photo 1' },
|
|
62
|
+
{ id: '2', src: '/photo2.jpg', alt: 'Photo 2' },
|
|
63
|
+
{ id: '3', src: '/video.mp4', alt: 'Video', type: 'video' },
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
function PhotoGallery() {
|
|
67
|
+
return (
|
|
68
|
+
<Gallery
|
|
69
|
+
images={images}
|
|
70
|
+
previewMode="carousel" // or "grid"
|
|
71
|
+
showThumbnails
|
|
72
|
+
enableLightbox
|
|
73
|
+
aspectRatio={16 / 9}
|
|
74
|
+
/>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Gallery Components
|
|
42
80
|
|
|
43
81
|
| Component | Description |
|
|
44
82
|
|-----------|-------------|
|
|
45
|
-
| `
|
|
83
|
+
| `Gallery` | Complete gallery with carousel/grid + lightbox |
|
|
84
|
+
| `GalleryCompact` | Minimal carousel for cards |
|
|
85
|
+
| `GalleryGrid` | Grid layout with "show more" badge |
|
|
86
|
+
| `GalleryLightbox` | Fullscreen lightbox viewer |
|
|
87
|
+
| `GalleryCarousel` | Embla-based carousel |
|
|
88
|
+
| `GalleryThumbnails` | Thumbnail strip navigation |
|
|
46
89
|
|
|
47
|
-
|
|
90
|
+
### Gallery Hooks
|
|
48
91
|
|
|
49
|
-
|
|
|
50
|
-
|
|
51
|
-
| `
|
|
92
|
+
| Hook | Description |
|
|
93
|
+
|------|-------------|
|
|
94
|
+
| `useGallery` | Gallery state management |
|
|
95
|
+
| `useSwipe` | Touch swipe gestures |
|
|
96
|
+
| `usePinchZoom` | Pinch-to-zoom for mobile |
|
|
97
|
+
| `usePreloadImages` | Image preloading |
|
|
98
|
+
|
|
99
|
+
## Map
|
|
52
100
|
|
|
53
|
-
|
|
101
|
+
MapLibre GL maps with React components for markers, clusters, popups, and custom layers.
|
|
54
102
|
|
|
55
103
|
```tsx
|
|
56
|
-
import {
|
|
57
|
-
|
|
104
|
+
import { MapContainer, MapMarker, MapPopup } from '@djangocfg/ui-tools/map';
|
|
105
|
+
|
|
106
|
+
const markers = [
|
|
107
|
+
{ id: '1', lat: 37.7749, lng: -122.4194, title: 'San Francisco' },
|
|
108
|
+
{ id: '2', lat: 34.0522, lng: -118.2437, title: 'Los Angeles' },
|
|
109
|
+
];
|
|
58
110
|
|
|
59
|
-
function
|
|
111
|
+
function LocationMap() {
|
|
60
112
|
return (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
113
|
+
<MapContainer
|
|
114
|
+
initialViewport={{ latitude: 36, longitude: -119, zoom: 5 }}
|
|
115
|
+
style="streets"
|
|
116
|
+
>
|
|
117
|
+
{markers.map((m) => (
|
|
118
|
+
<MapMarker key={m.id} latitude={m.lat} longitude={m.lng}>
|
|
119
|
+
<MapPopup>{m.title}</MapPopup>
|
|
120
|
+
</MapMarker>
|
|
121
|
+
))}
|
|
122
|
+
</MapContainer>
|
|
67
123
|
);
|
|
68
124
|
}
|
|
69
125
|
```
|
|
70
126
|
|
|
71
|
-
|
|
127
|
+
### Map Components
|
|
128
|
+
|
|
129
|
+
| Component | Description |
|
|
130
|
+
|-----------|-------------|
|
|
131
|
+
| `MapContainer` | Main map container with controls |
|
|
132
|
+
| `MapMarker` | Custom marker with React children |
|
|
133
|
+
| `MapPopup` | Popup attached to marker |
|
|
134
|
+
| `MapCluster` | Clustered markers |
|
|
135
|
+
| `MapSource` / `MapLayer` | Custom GeoJSON layers |
|
|
136
|
+
| `MapControls` | Navigation controls |
|
|
137
|
+
| `MapLegend` | Map legend component |
|
|
138
|
+
| `LayerSwitcher` | Toggle map layers |
|
|
139
|
+
| `DrawControl` | Drawing tools (optional) |
|
|
140
|
+
| `GeocoderControl` | Search/geocoding (optional) |
|
|
141
|
+
|
|
142
|
+
### Map Hooks
|
|
143
|
+
|
|
144
|
+
| Hook | Description |
|
|
145
|
+
|------|-------------|
|
|
146
|
+
| `useMap` | Access map instance |
|
|
147
|
+
| `useMapControl` | Programmatic map control |
|
|
148
|
+
| `useMarkers` | Marker management |
|
|
149
|
+
| `useMapEvents` | Map event handlers |
|
|
150
|
+
| `useMapViewport` | Viewport state |
|
|
151
|
+
| `useMapLayers` | Layer management |
|
|
152
|
+
|
|
153
|
+
### Map Styles
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { MAP_STYLES, getMapStyle } from '@djangocfg/ui-tools/map';
|
|
157
|
+
|
|
158
|
+
// Available styles: streets, satellite, dark, light, terrain
|
|
159
|
+
<MapContainer style="dark" />
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Layer Utilities
|
|
72
163
|
|
|
73
164
|
```tsx
|
|
74
|
-
import {
|
|
165
|
+
import {
|
|
166
|
+
createClusterLayers,
|
|
167
|
+
createPointLayer,
|
|
168
|
+
createPolygonLayer,
|
|
169
|
+
createLineLayer,
|
|
170
|
+
} from '@djangocfg/ui-tools/map';
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Video Player
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import { VideoPlayer } from '@djangocfg/ui-tools';
|
|
177
|
+
|
|
178
|
+
<VideoPlayer
|
|
179
|
+
src="https://example.com/video.mp4"
|
|
180
|
+
poster="/thumbnail.jpg"
|
|
181
|
+
autoplay={false}
|
|
182
|
+
/>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Audio Player
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
import { HybridAudioPlayer } from '@djangocfg/ui-tools';
|
|
189
|
+
|
|
190
|
+
<HybridAudioPlayer
|
|
191
|
+
src="https://example.com/audio.mp3"
|
|
192
|
+
showWaveform
|
|
193
|
+
/>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Mermaid Diagrams
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { Mermaid } from '@djangocfg/ui-tools';
|
|
200
|
+
|
|
201
|
+
<Mermaid chart={`
|
|
202
|
+
graph TD
|
|
203
|
+
A[Start] --> B{Decision}
|
|
204
|
+
B -->|Yes| C[Action]
|
|
205
|
+
B -->|No| D[End]
|
|
206
|
+
`} />
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Code Highlighting
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
import { PrettyCode } from '@djangocfg/ui-tools';
|
|
213
|
+
|
|
214
|
+
<PrettyCode
|
|
215
|
+
code={`const hello = "world";`}
|
|
216
|
+
language="typescript"
|
|
217
|
+
/>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## JSON Form
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import { JsonSchemaForm } from '@djangocfg/ui-tools';
|
|
75
224
|
|
|
76
225
|
const schema = {
|
|
77
226
|
type: 'object',
|
|
@@ -81,42 +230,76 @@ const schema = {
|
|
|
81
230
|
},
|
|
82
231
|
};
|
|
83
232
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
onSubmit={(data) => console.log(data)}
|
|
89
|
-
/>
|
|
90
|
-
);
|
|
91
|
-
}
|
|
233
|
+
<JsonSchemaForm
|
|
234
|
+
schema={schema}
|
|
235
|
+
onSubmit={(data) => console.log(data)}
|
|
236
|
+
/>
|
|
92
237
|
```
|
|
93
238
|
|
|
94
|
-
##
|
|
239
|
+
## Components
|
|
95
240
|
|
|
96
|
-
|
|
97
|
-
|
|
241
|
+
| Component | Description |
|
|
242
|
+
|-----------|-------------|
|
|
243
|
+
| `Markdown` | Markdown renderer with GFM support |
|
|
98
244
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
/>
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
```
|
|
245
|
+
## Stores
|
|
246
|
+
|
|
247
|
+
| Store | Description |
|
|
248
|
+
|-------|-------------|
|
|
249
|
+
| `useMediaCacheStore` | Media caching for video/audio players |
|
|
108
250
|
|
|
109
251
|
## Lazy Loading
|
|
110
252
|
|
|
111
|
-
All tools
|
|
253
|
+
All heavy tools have unified lazy-loaded versions with built-in Suspense fallbacks:
|
|
254
|
+
|
|
255
|
+
```tsx
|
|
256
|
+
import {
|
|
257
|
+
LazyMapContainer, // ~800KB
|
|
258
|
+
LazyMermaid, // ~800KB
|
|
259
|
+
LazyPrettyCode, // ~500KB
|
|
260
|
+
LazyOpenapiViewer, // ~400KB
|
|
261
|
+
LazyJsonSchemaForm, // ~300KB
|
|
262
|
+
LazyLottiePlayer, // ~200KB
|
|
263
|
+
LazyHybridAudioPlayer, // ~200KB
|
|
264
|
+
LazyVideoPlayer, // ~150KB
|
|
265
|
+
LazyJsonTree, // ~100KB
|
|
266
|
+
LazyImageViewer, // ~50KB
|
|
267
|
+
} from '@djangocfg/ui-tools';
|
|
268
|
+
|
|
269
|
+
// Just use them - no Suspense wrapper needed!
|
|
270
|
+
<LazyMermaid chart={diagram} />
|
|
271
|
+
<LazyMapContainer initialViewport={viewport} />
|
|
272
|
+
<LazyVideoPlayer src="/video.mp4" />
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Custom Lazy Components
|
|
276
|
+
|
|
277
|
+
Create your own lazy components with `createLazyComponent`:
|
|
112
278
|
|
|
113
279
|
```tsx
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
280
|
+
import { createLazyComponent, CardLoadingFallback } from '@djangocfg/ui-tools';
|
|
281
|
+
|
|
282
|
+
const LazyMyComponent = createLazyComponent(
|
|
283
|
+
() => import('./MyHeavyComponent'),
|
|
284
|
+
{
|
|
285
|
+
displayName: 'LazyMyComponent',
|
|
286
|
+
fallback: <CardLoadingFallback title="Loading..." minHeight={200} />,
|
|
287
|
+
}
|
|
288
|
+
);
|
|
118
289
|
```
|
|
119
290
|
|
|
291
|
+
### Loading Fallbacks
|
|
292
|
+
|
|
293
|
+
Built-in fallback components for different use cases:
|
|
294
|
+
|
|
295
|
+
| Component | Use Case |
|
|
296
|
+
|-----------|----------|
|
|
297
|
+
| `LoadingFallback` | Generic spinner with optional text |
|
|
298
|
+
| `CardLoadingFallback` | Card-styled loading with title |
|
|
299
|
+
| `MapLoadingFallback` | Map-specific with location icon |
|
|
300
|
+
| `Spinner` | Simple spinning loader |
|
|
301
|
+
| `LazyWrapper` | Suspense wrapper with configurable fallback |
|
|
302
|
+
|
|
120
303
|
## Requirements
|
|
121
304
|
|
|
122
305
|
- React >= 18 or >= 19
|
|
@@ -124,6 +307,16 @@ All tools use React.lazy + Suspense for automatic code splitting:
|
|
|
124
307
|
- Zustand >= 5
|
|
125
308
|
- @djangocfg/ui-core (peer dependency)
|
|
126
309
|
|
|
127
|
-
|
|
310
|
+
### Optional Dependencies (for Map)
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
# For drawing tools
|
|
314
|
+
pnpm add @mapbox/mapbox-gl-draw
|
|
315
|
+
|
|
316
|
+
# For geocoding/search
|
|
317
|
+
pnpm add @maplibre/maplibre-gl-geocoder
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## License
|
|
128
321
|
|
|
129
|
-
|
|
322
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"JsonSchemaForm-65NLLK56.mjs"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkPNZSJN6T_cjs = require('./chunk-PNZSJN6T.cjs');
|
|
4
|
+
require('./chunk-WGEGR3DF.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Object.defineProperty(exports, "JsonSchemaForm", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return chunkPNZSJN6T_cjs.JsonSchemaForm; }
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=JsonSchemaForm-PY6DH3HE.cjs.map
|
|
13
|
+
//# sourceMappingURL=JsonSchemaForm-PY6DH3HE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"JsonSchemaForm-PY6DH3HE.cjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"JsonTree-6RYAOPSS.mjs"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk5QT3QYFZ_cjs = require('./chunk-5QT3QYFZ.cjs');
|
|
4
|
+
require('./chunk-WGEGR3DF.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
module.exports = chunk5QT3QYFZ_cjs.JsonTree_default;
|
|
9
|
+
//# sourceMappingURL=JsonTree-7OH6CIHT.cjs.map
|
|
10
|
+
//# sourceMappingURL=JsonTree-7OH6CIHT.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"JsonTree-7OH6CIHT.cjs"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { __name } from './chunk-CGILA3WO.mjs';
|
|
2
|
+
import { createContext, useRef, useState, useCallback, useMemo, useContext, useEffect } from 'react';
|
|
3
|
+
import Map from 'react-map-gl/maplibre';
|
|
4
|
+
import { RotateCcw, ExternalLink } from 'lucide-react';
|
|
5
|
+
import { cn } from '@djangocfg/ui-core/lib';
|
|
6
|
+
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
|
|
9
|
+
var MapContext = createContext(null);
|
|
10
|
+
var DEFAULT_VIEWPORT = {
|
|
11
|
+
longitude: 115.1889,
|
|
12
|
+
latitude: -8.4095,
|
|
13
|
+
zoom: 10,
|
|
14
|
+
bearing: 0,
|
|
15
|
+
pitch: 0
|
|
16
|
+
};
|
|
17
|
+
function MapProvider({ children, initialViewport }) {
|
|
18
|
+
const mapRef = useRef(null);
|
|
19
|
+
const initialViewportRef = useRef({
|
|
20
|
+
...DEFAULT_VIEWPORT,
|
|
21
|
+
...initialViewport
|
|
22
|
+
});
|
|
23
|
+
const [viewport, setViewportState] = useState(initialViewportRef.current);
|
|
24
|
+
const [markers, setMarkers] = useState([]);
|
|
25
|
+
const [selectedMarker, setSelectedMarker] = useState(null);
|
|
26
|
+
const [hoveredFeature, setHoveredFeature] = useState(null);
|
|
27
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
28
|
+
const setViewport = useCallback((newViewport) => {
|
|
29
|
+
setViewportState((prev) => ({ ...prev, ...newViewport }));
|
|
30
|
+
}, []);
|
|
31
|
+
const resetToInitial = useCallback(() => {
|
|
32
|
+
const map = mapRef.current;
|
|
33
|
+
if (map) {
|
|
34
|
+
map.flyTo({
|
|
35
|
+
center: [initialViewportRef.current.longitude, initialViewportRef.current.latitude],
|
|
36
|
+
zoom: initialViewportRef.current.zoom,
|
|
37
|
+
bearing: initialViewportRef.current.bearing ?? 0,
|
|
38
|
+
pitch: initialViewportRef.current.pitch ?? 0,
|
|
39
|
+
duration: 1e3
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}, []);
|
|
43
|
+
const value = useMemo(
|
|
44
|
+
() => ({
|
|
45
|
+
mapRef,
|
|
46
|
+
viewport,
|
|
47
|
+
setViewport,
|
|
48
|
+
initialViewport: initialViewportRef.current,
|
|
49
|
+
resetToInitial,
|
|
50
|
+
markers,
|
|
51
|
+
setMarkers,
|
|
52
|
+
selectedMarker,
|
|
53
|
+
setSelectedMarker,
|
|
54
|
+
hoveredFeature,
|
|
55
|
+
setHoveredFeature,
|
|
56
|
+
isLoaded,
|
|
57
|
+
setIsLoaded
|
|
58
|
+
}),
|
|
59
|
+
[viewport, setViewport, resetToInitial, markers, selectedMarker, hoveredFeature, isLoaded]
|
|
60
|
+
);
|
|
61
|
+
return /* @__PURE__ */ jsx(MapContext.Provider, { value, children });
|
|
62
|
+
}
|
|
63
|
+
__name(MapProvider, "MapProvider");
|
|
64
|
+
function useMapContext() {
|
|
65
|
+
const context = useContext(MapContext);
|
|
66
|
+
if (!context) {
|
|
67
|
+
throw new Error("useMapContext must be used within a MapProvider");
|
|
68
|
+
}
|
|
69
|
+
return context;
|
|
70
|
+
}
|
|
71
|
+
__name(useMapContext, "useMapContext");
|
|
72
|
+
|
|
73
|
+
// src/tools/Map/styles/index.ts
|
|
74
|
+
var MAP_STYLES = {
|
|
75
|
+
light: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
|
|
76
|
+
dark: "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",
|
|
77
|
+
streets: "https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json",
|
|
78
|
+
satellite: "https://api.maptiler.com/maps/satellite/style.json"
|
|
79
|
+
};
|
|
80
|
+
function MapInner({
|
|
81
|
+
children,
|
|
82
|
+
mapStyle = "light",
|
|
83
|
+
interactiveLayerIds,
|
|
84
|
+
style,
|
|
85
|
+
cursor,
|
|
86
|
+
attributionControl = true,
|
|
87
|
+
reuseMaps = true,
|
|
88
|
+
openInMapsUrl,
|
|
89
|
+
openInMapsLabel = "Open in Maps",
|
|
90
|
+
autoResetDelay = 0,
|
|
91
|
+
showResetButton = false
|
|
92
|
+
}) {
|
|
93
|
+
const { mapRef, viewport, setViewport, setIsLoaded, resetToInitial, initialViewport } = useMapContext();
|
|
94
|
+
const resetTimerRef = useRef(null);
|
|
95
|
+
const isInteractingRef = useRef(false);
|
|
96
|
+
const hasViewportChanged = Math.abs(viewport.longitude - initialViewport.longitude) > 1e-4 || Math.abs(viewport.latitude - initialViewport.latitude) > 1e-4 || Math.abs(viewport.zoom - initialViewport.zoom) > 0.1;
|
|
97
|
+
const handleMove = useCallback(
|
|
98
|
+
(evt) => {
|
|
99
|
+
setViewport({
|
|
100
|
+
longitude: evt.viewState.longitude,
|
|
101
|
+
latitude: evt.viewState.latitude,
|
|
102
|
+
zoom: evt.viewState.zoom,
|
|
103
|
+
bearing: evt.viewState.bearing,
|
|
104
|
+
pitch: evt.viewState.pitch
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
[setViewport]
|
|
108
|
+
);
|
|
109
|
+
const handleMoveStart = useCallback(() => {
|
|
110
|
+
isInteractingRef.current = true;
|
|
111
|
+
if (resetTimerRef.current) {
|
|
112
|
+
clearTimeout(resetTimerRef.current);
|
|
113
|
+
resetTimerRef.current = null;
|
|
114
|
+
}
|
|
115
|
+
}, []);
|
|
116
|
+
const handleMoveEnd = useCallback(() => {
|
|
117
|
+
isInteractingRef.current = false;
|
|
118
|
+
if (autoResetDelay > 0) {
|
|
119
|
+
resetTimerRef.current = setTimeout(() => {
|
|
120
|
+
if (!isInteractingRef.current) {
|
|
121
|
+
resetToInitial();
|
|
122
|
+
}
|
|
123
|
+
}, autoResetDelay);
|
|
124
|
+
}
|
|
125
|
+
}, [autoResetDelay, resetToInitial]);
|
|
126
|
+
const handleLoad = useCallback(() => {
|
|
127
|
+
setIsLoaded(true);
|
|
128
|
+
}, [setIsLoaded]);
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
return () => {
|
|
131
|
+
if (resetTimerRef.current) {
|
|
132
|
+
clearTimeout(resetTimerRef.current);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}, []);
|
|
136
|
+
const resolvedStyle = mapStyle in MAP_STYLES ? MAP_STYLES[mapStyle] : mapStyle;
|
|
137
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138
|
+
/* @__PURE__ */ jsx(
|
|
139
|
+
Map,
|
|
140
|
+
{
|
|
141
|
+
ref: mapRef,
|
|
142
|
+
...viewport,
|
|
143
|
+
onMove: handleMove,
|
|
144
|
+
onMoveStart: handleMoveStart,
|
|
145
|
+
onMoveEnd: handleMoveEnd,
|
|
146
|
+
onLoad: handleLoad,
|
|
147
|
+
mapStyle: resolvedStyle,
|
|
148
|
+
interactiveLayerIds,
|
|
149
|
+
attributionControl: attributionControl ? {} : false,
|
|
150
|
+
reuseMaps,
|
|
151
|
+
style: {
|
|
152
|
+
width: "100%",
|
|
153
|
+
height: "100%",
|
|
154
|
+
...style
|
|
155
|
+
},
|
|
156
|
+
cursor,
|
|
157
|
+
children
|
|
158
|
+
}
|
|
159
|
+
),
|
|
160
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-3 right-3 flex items-center gap-2", children: [
|
|
161
|
+
showResetButton && hasViewportChanged && /* @__PURE__ */ jsxs(
|
|
162
|
+
"button",
|
|
163
|
+
{
|
|
164
|
+
type: "button",
|
|
165
|
+
onClick: resetToInitial,
|
|
166
|
+
className: cn(
|
|
167
|
+
"inline-flex items-center gap-2 px-3 py-2 rounded-lg",
|
|
168
|
+
"bg-background/95 backdrop-blur-sm text-foreground text-sm font-medium",
|
|
169
|
+
"hover:bg-background transition-colors shadow-sm border border-border"
|
|
170
|
+
),
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ jsx(RotateCcw, { className: "w-4 h-4" }),
|
|
173
|
+
"Reset"
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
),
|
|
177
|
+
openInMapsUrl && /* @__PURE__ */ jsxs(
|
|
178
|
+
"a",
|
|
179
|
+
{
|
|
180
|
+
href: openInMapsUrl,
|
|
181
|
+
target: "_blank",
|
|
182
|
+
rel: "noopener noreferrer",
|
|
183
|
+
className: cn(
|
|
184
|
+
"inline-flex items-center gap-2 px-4 py-2 rounded-lg",
|
|
185
|
+
"bg-background/95 backdrop-blur-sm text-foreground text-sm font-medium",
|
|
186
|
+
"hover:bg-background transition-colors shadow-sm border border-border"
|
|
187
|
+
),
|
|
188
|
+
children: [
|
|
189
|
+
/* @__PURE__ */ jsx(ExternalLink, { className: "w-4 h-4" }),
|
|
190
|
+
openInMapsLabel
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
] })
|
|
195
|
+
] });
|
|
196
|
+
}
|
|
197
|
+
__name(MapInner, "MapInner");
|
|
198
|
+
function MapContainer({
|
|
199
|
+
children,
|
|
200
|
+
initialViewport,
|
|
201
|
+
className,
|
|
202
|
+
...props
|
|
203
|
+
}) {
|
|
204
|
+
return /* @__PURE__ */ jsx("div", { className, style: { width: "100%", height: "100%", position: "relative" }, children: /* @__PURE__ */ jsx(MapProvider, { initialViewport, children: /* @__PURE__ */ jsx(MapInner, { ...props, children }) }) });
|
|
205
|
+
}
|
|
206
|
+
__name(MapContainer, "MapContainer");
|
|
207
|
+
function MapView(props) {
|
|
208
|
+
return /* @__PURE__ */ jsx(MapInner, { ...props });
|
|
209
|
+
}
|
|
210
|
+
__name(MapView, "MapView");
|
|
211
|
+
|
|
212
|
+
export { MapContainer, MapView };
|
|
213
|
+
//# sourceMappingURL=MapContainer-GXQLP5WY.mjs.map
|
|
214
|
+
//# sourceMappingURL=MapContainer-GXQLP5WY.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tools/Map/context/MapContext.tsx","../src/tools/Map/styles/index.ts","../src/tools/Map/components/MapContainer.tsx"],"names":["useRef","useCallback","jsx"],"mappings":"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","file":"MapContainer-GXQLP5WY.mjs","sourcesContent":["'use client'\n\nimport {\n createContext,\n useContext,\n useState,\n useRef,\n useMemo,\n useCallback,\n type ReactNode,\n} from 'react'\nimport type { MapRef } from 'react-map-gl/maplibre'\nimport type { MapContextValue, MapViewport, MarkerData } from '../types'\n\nconst MapContext = createContext<MapContextValue | null>(null)\n\nexport interface MapProviderProps {\n children: ReactNode\n initialViewport?: Partial<MapViewport>\n}\n\nconst DEFAULT_VIEWPORT: MapViewport = {\n longitude: 115.1889,\n latitude: -8.4095,\n zoom: 10,\n bearing: 0,\n pitch: 0,\n}\n\nexport function MapProvider({ children, initialViewport }: MapProviderProps) {\n const mapRef = useRef<MapRef | null>(null)\n const initialViewportRef = useRef<MapViewport>({\n ...DEFAULT_VIEWPORT,\n ...initialViewport,\n })\n const [viewport, setViewportState] = useState<MapViewport>(initialViewportRef.current)\n const [markers, setMarkers] = useState<MarkerData[]>([])\n const [selectedMarker, setSelectedMarker] = useState<MarkerData | null>(null)\n const [hoveredFeature, setHoveredFeature] = useState<GeoJSON.Feature | null>(null)\n const [isLoaded, setIsLoaded] = useState(false)\n\n const setViewport = useCallback((newViewport: Partial<MapViewport>) => {\n setViewportState((prev) => ({ ...prev, ...newViewport }))\n }, [])\n\n const resetToInitial = useCallback(() => {\n const map = mapRef.current\n if (map) {\n map.flyTo({\n center: [initialViewportRef.current.longitude, initialViewportRef.current.latitude],\n zoom: initialViewportRef.current.zoom,\n bearing: initialViewportRef.current.bearing ?? 0,\n pitch: initialViewportRef.current.pitch ?? 0,\n duration: 1000,\n })\n }\n }, [])\n\n const value = useMemo<MapContextValue>(\n () => ({\n mapRef,\n viewport,\n setViewport,\n initialViewport: initialViewportRef.current,\n resetToInitial,\n markers,\n setMarkers,\n selectedMarker,\n setSelectedMarker,\n hoveredFeature,\n setHoveredFeature,\n isLoaded,\n setIsLoaded,\n }),\n [viewport, setViewport, resetToInitial, markers, selectedMarker, hoveredFeature, isLoaded]\n )\n\n return <MapContext.Provider value={value}>{children}</MapContext.Provider>\n}\n\nexport function useMapContext(): MapContextValue {\n const context = useContext(MapContext)\n if (!context) {\n throw new Error('useMapContext must be used within a MapProvider')\n }\n return context\n}\n\nexport { MapContext }\n","export const MAP_STYLES = {\n light: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',\n dark: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',\n streets: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json',\n satellite: 'https://api.maptiler.com/maps/satellite/style.json',\n} as const\n\nexport type MapStyleKey = keyof typeof MAP_STYLES\n\nexport function getMapStyle(key: MapStyleKey | string): string {\n if (key in MAP_STYLES) {\n return MAP_STYLES[key as MapStyleKey]\n }\n return key\n}\n","'use client'\n\nimport { useCallback, useEffect, useRef, type ReactNode } from 'react'\nimport Map, { type ViewStateChangeEvent } from 'react-map-gl/maplibre'\nimport { ExternalLink, RotateCcw } from 'lucide-react'\nimport { cn } from '@djangocfg/ui-core/lib'\nimport 'maplibre-gl/dist/maplibre-gl.css'\n\nimport { MapProvider, useMapContext } from '../context'\nimport { MAP_STYLES } from '../styles'\nimport type { MapViewport, MapStyleKey } from '../types'\n\nexport interface MapContainerProps {\n children?: ReactNode\n initialViewport?: Partial<MapViewport>\n mapStyle?: MapStyleKey | string\n interactiveLayerIds?: string[]\n className?: string\n style?: React.CSSProperties\n cursor?: string\n attributionControl?: boolean\n reuseMaps?: boolean\n /** URL to open in external maps app (shows \"Open in Maps\" button if provided) */\n openInMapsUrl?: string\n /** Label for the open in maps button */\n openInMapsLabel?: string\n /** Auto-reset to initial viewport after N ms of inactivity (0 = disabled) */\n autoResetDelay?: number\n /** Show reset button */\n showResetButton?: boolean\n}\n\ninterface MapInnerProps extends Omit<MapContainerProps, 'initialViewport'> {}\n\nfunction MapInner({\n children,\n mapStyle = 'light',\n interactiveLayerIds,\n style,\n cursor,\n attributionControl = true,\n reuseMaps = true,\n openInMapsUrl,\n openInMapsLabel = 'Open in Maps',\n autoResetDelay = 0,\n showResetButton = false,\n}: MapInnerProps) {\n const { mapRef, viewport, setViewport, setIsLoaded, resetToInitial, initialViewport } = useMapContext()\n const resetTimerRef = useRef<NodeJS.Timeout | null>(null)\n const isInteractingRef = useRef(false)\n\n // Check if viewport has changed from initial\n const hasViewportChanged =\n Math.abs(viewport.longitude - initialViewport.longitude) > 0.0001 ||\n Math.abs(viewport.latitude - initialViewport.latitude) > 0.0001 ||\n Math.abs(viewport.zoom - initialViewport.zoom) > 0.1\n\n const handleMove = useCallback(\n (evt: ViewStateChangeEvent) => {\n setViewport({\n longitude: evt.viewState.longitude,\n latitude: evt.viewState.latitude,\n zoom: evt.viewState.zoom,\n bearing: evt.viewState.bearing,\n pitch: evt.viewState.pitch,\n })\n },\n [setViewport]\n )\n\n const handleMoveStart = useCallback(() => {\n isInteractingRef.current = true\n // Clear any pending reset timer\n if (resetTimerRef.current) {\n clearTimeout(resetTimerRef.current)\n resetTimerRef.current = null\n }\n }, [])\n\n const handleMoveEnd = useCallback(() => {\n isInteractingRef.current = false\n // Start auto-reset timer if enabled\n if (autoResetDelay > 0) {\n resetTimerRef.current = setTimeout(() => {\n if (!isInteractingRef.current) {\n resetToInitial()\n }\n }, autoResetDelay)\n }\n }, [autoResetDelay, resetToInitial])\n\n const handleLoad = useCallback(() => {\n setIsLoaded(true)\n }, [setIsLoaded])\n\n // Cleanup timer on unmount\n useEffect(() => {\n return () => {\n if (resetTimerRef.current) {\n clearTimeout(resetTimerRef.current)\n }\n }\n }, [])\n\n const resolvedStyle = mapStyle in MAP_STYLES\n ? MAP_STYLES[mapStyle as MapStyleKey]\n : mapStyle\n\n return (\n <>\n <Map\n ref={mapRef}\n {...viewport}\n onMove={handleMove}\n onMoveStart={handleMoveStart}\n onMoveEnd={handleMoveEnd}\n onLoad={handleLoad}\n mapStyle={resolvedStyle}\n interactiveLayerIds={interactiveLayerIds}\n attributionControl={attributionControl ? {} : false}\n reuseMaps={reuseMaps}\n style={{\n width: '100%',\n height: '100%',\n ...style,\n }}\n cursor={cursor}\n >\n {children}\n </Map>\n\n {/* Map overlay buttons */}\n <div className=\"absolute bottom-3 right-3 flex items-center gap-2\">\n {/* Reset button */}\n {showResetButton && hasViewportChanged && (\n <button\n type=\"button\"\n onClick={resetToInitial}\n className={cn(\n 'inline-flex items-center gap-2 px-3 py-2 rounded-lg',\n 'bg-background/95 backdrop-blur-sm text-foreground text-sm font-medium',\n 'hover:bg-background transition-colors shadow-sm border border-border'\n )}\n >\n <RotateCcw className=\"w-4 h-4\" />\n Reset\n </button>\n )}\n\n {/* Open in Maps button */}\n {openInMapsUrl && (\n <a\n href={openInMapsUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cn(\n 'inline-flex items-center gap-2 px-4 py-2 rounded-lg',\n 'bg-background/95 backdrop-blur-sm text-foreground text-sm font-medium',\n 'hover:bg-background transition-colors shadow-sm border border-border'\n )}\n >\n <ExternalLink className=\"w-4 h-4\" />\n {openInMapsLabel}\n </a>\n )}\n </div>\n </>\n )\n}\n\nexport function MapContainer({\n children,\n initialViewport,\n className,\n ...props\n}: MapContainerProps) {\n return (\n <div className={className} style={{ width: '100%', height: '100%', position: 'relative' }}>\n <MapProvider initialViewport={initialViewport}>\n <MapInner {...props}>{children}</MapInner>\n </MapProvider>\n </div>\n )\n}\n\n/**\n * Use this when you need the map inside an existing MapProvider\n */\nexport function MapView(props: Omit<MapContainerProps, 'initialViewport'>) {\n return <MapInner {...props} />\n}\n"]}
|