@djangocfg/ui-tools 2.1.385 → 2.1.387

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.
Files changed (52) hide show
  1. package/README.md +25 -11
  2. package/dist/ChatRoot-4KM2JMGA.mjs +6 -0
  3. package/dist/{ChatRoot-JVR3M3H2.mjs.map → ChatRoot-4KM2JMGA.mjs.map} +1 -1
  4. package/dist/ChatRoot-OILWMMZ6.cjs +15 -0
  5. package/dist/{ChatRoot-LXIUBOXF.cjs.map → ChatRoot-OILWMMZ6.cjs.map} +1 -1
  6. package/dist/MapContainer-AKIPABJK.mjs +4 -0
  7. package/dist/MapContainer-AKIPABJK.mjs.map +1 -0
  8. package/dist/MapContainer-STVDMC36.cjs +17 -0
  9. package/dist/MapContainer-STVDMC36.cjs.map +1 -0
  10. package/dist/{MapContainer-76YL2JXL.cjs → chunk-5D2OCOPQ.cjs} +3 -2
  11. package/dist/chunk-5D2OCOPQ.cjs.map +1 -0
  12. package/dist/{MapContainer-7HXBI3OH.mjs → chunk-7CWGZPO3.mjs} +3 -3
  13. package/dist/chunk-7CWGZPO3.mjs.map +1 -0
  14. package/dist/chunk-BVESQTBM.mjs +1439 -0
  15. package/dist/chunk-BVESQTBM.mjs.map +1 -0
  16. package/dist/{chunk-PEKBT75W.mjs → chunk-DMX7W4XZ.mjs} +53 -1387
  17. package/dist/chunk-DMX7W4XZ.mjs.map +1 -0
  18. package/dist/chunk-HNIMIIFR.mjs +1361 -0
  19. package/dist/chunk-HNIMIIFR.mjs.map +1 -0
  20. package/dist/chunk-L25HA3TM.cjs +1478 -0
  21. package/dist/chunk-L25HA3TM.cjs.map +1 -0
  22. package/dist/{chunk-HPK3EWBF.cjs → chunk-TBSHZO5R.cjs} +50 -1409
  23. package/dist/chunk-TBSHZO5R.cjs.map +1 -0
  24. package/dist/chunk-TSNRU3UO.cjs +1387 -0
  25. package/dist/chunk-TSNRU3UO.cjs.map +1 -0
  26. package/dist/index.cjs +1236 -1769
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +780 -780
  29. package/dist/index.d.ts +780 -780
  30. package/dist/index.mjs +853 -1424
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/launcher-5WYPDPEP.mjs +7 -0
  33. package/dist/launcher-5WYPDPEP.mjs.map +1 -0
  34. package/dist/launcher-FCI3LTDY.css +7 -0
  35. package/dist/launcher-FCI3LTDY.css.map +1 -0
  36. package/dist/launcher-QAOG2NUI.cjs +60 -0
  37. package/dist/launcher-QAOG2NUI.cjs.map +1 -0
  38. package/package.json +23 -18
  39. package/src/tools/AudioPlayer/lazy.tsx +100 -0
  40. package/src/tools/Chat/README.md +85 -1
  41. package/src/tools/Chat/context/ChatProvider.tsx +42 -0
  42. package/src/tools/Chat/lazy.tsx +213 -1
  43. package/src/tools/CodeEditor/lazy.tsx +70 -0
  44. package/src/tools/Map/lazy.tsx +38 -1
  45. package/src/tools/MarkdownEditor/lazy.tsx +42 -0
  46. package/src/tools/SpeechRecognition/README.md +48 -0
  47. package/dist/ChatRoot-JVR3M3H2.mjs +0 -5
  48. package/dist/ChatRoot-LXIUBOXF.cjs +0 -14
  49. package/dist/MapContainer-76YL2JXL.cjs.map +0 -1
  50. package/dist/MapContainer-7HXBI3OH.mjs.map +0 -1
  51. package/dist/chunk-HPK3EWBF.cjs.map +0 -1
  52. package/dist/chunk-PEKBT75W.mjs.map +0 -1
@@ -0,0 +1,70 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * `@djangocfg/ui-tools/code-editor` subpath entrypoint.
5
+ *
6
+ * Monaco itself weighs ~550 KB minified — we must never pay that cost
7
+ * unless the editor actually mounts. The `Lazy*` wrappers here dynamically
8
+ * import the `Editor` and `DiffEditor` components, which transitively pull
9
+ * in `monaco-editor` and the worker setup.
10
+ *
11
+ * The rest of the surface (types, EditorProvider, useMonaco hook, helpers)
12
+ * is light:
13
+ * - `monaco-editor` is referenced only as a TS type (`type *`) — erased
14
+ * at compile time.
15
+ * - `useMonaco` performs a dynamic `import('monaco-editor')` itself, so
16
+ * importing the hook is free until the caller actually invokes it.
17
+ *
18
+ * That means consumers can wire up keyboard shortcuts, theme toggles, or
19
+ * file-state hooks at the top of their tree without paying Monaco's cost,
20
+ * and only render `<LazyEditor>` lower in the tree where it's needed.
21
+ */
22
+
23
+ import { createLazyComponent, LoadingFallback } from '../../components';
24
+ import type { EditorProps, DiffEditorProps } from './types';
25
+
26
+ // ============================================================================
27
+ // Lazy components
28
+ // ============================================================================
29
+
30
+ export const LazyEditor = createLazyComponent<EditorProps>(
31
+ () => import('./components/Editor').then((m) => ({ default: m.Editor })),
32
+ {
33
+ displayName: 'LazyEditor',
34
+ fallback: <LoadingFallback minHeight={320} text="Loading editor…" />,
35
+ },
36
+ );
37
+
38
+ export const LazyDiffEditor = createLazyComponent<DiffEditorProps>(
39
+ () => import('./components/DiffEditor').then((m) => ({ default: m.DiffEditor })),
40
+ {
41
+ displayName: 'LazyDiffEditor',
42
+ fallback: <LoadingFallback minHeight={320} text="Loading diff editor…" />,
43
+ },
44
+ );
45
+
46
+ // ============================================================================
47
+ // Light surface
48
+ // ============================================================================
49
+
50
+ // Hooks — `useMonaco` does its own dynamic import; the others are pure.
51
+ export {
52
+ useMonaco,
53
+ useEditor,
54
+ useLanguage,
55
+ useEditorTheme,
56
+ } from './hooks';
57
+
58
+ // Provider + context hook
59
+ export { EditorProvider, useEditorContext } from './context';
60
+
61
+ // All types
62
+ export type {
63
+ EditorFile,
64
+ EditorOptions,
65
+ EditorProps,
66
+ EditorContextValue,
67
+ UseEditorReturn,
68
+ UseMonacoReturn,
69
+ DiffEditorProps,
70
+ } from './types';
@@ -42,11 +42,48 @@ export const LazyMapView = createLazyComponent(
42
42
  );
43
43
 
44
44
  // ============================================================================
45
- // Re-export types for convenience
45
+ // Light primitives direct re-exports
46
+ //
47
+ // MapMarker / MapPopup / MapCluster / MapSource / MapLayer / MapControls
48
+ // etc. are thin wrappers around `react-map-gl/maplibre`. They don't import
49
+ // `maplibre-gl` at module scope (only types, which are erased), so exporting
50
+ // them synchronously here costs ~tens of KB at most — not the ~800KB of
51
+ // MapLibre GL itself.
52
+ //
53
+ // The heavy library only loads when `LazyMapContainer` actually mounts,
54
+ // because `MapContainer.tsx` (the only module that imports `maplibre-gl`
55
+ // at runtime) is reached exclusively via the dynamic import above.
56
+ //
57
+ // This means consumers can write:
58
+ //
59
+ // import { LazyMapContainer, MapMarker, MapPopup } from '@djangocfg/ui-tools/map'
60
+ //
61
+ // …and still get correct code-splitting.
46
62
  // ============================================================================
47
63
 
64
+ export {
65
+ MapMarker,
66
+ MapPopup,
67
+ MapCluster,
68
+ MapSource,
69
+ MapLayer,
70
+ MapControls,
71
+ CustomOverlay,
72
+ MapLegend,
73
+ LayerSwitcher,
74
+ } from './components';
75
+
76
+ export { MapProvider, useMapContext, MapContext } from './context';
77
+ export type { MapProviderProps } from './context';
78
+
48
79
  export type {
49
80
  MapContainerProps,
81
+ MapMarkerProps,
82
+ MapPopupProps,
83
+ MapClusterProps,
84
+ MapSourceProps,
85
+ MapLayerProps,
86
+ MapControlsProps,
50
87
  } from './components';
51
88
 
52
89
  export type {
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * `@djangocfg/ui-tools/markdown-editor` subpath entrypoint.
5
+ *
6
+ * `MarkdownEditor` is a TipTap WYSIWYG with the full ProseMirror + TipTap
7
+ * extension stack — `@tiptap/react`, `starter-kit`, `markdown`, `mention`,
8
+ * `placeholder`, plus our `createMentionSuggestion` (floating-ui anchored
9
+ * dropdown). Together that's ~200 KB minified — wrap it in React.lazy so
10
+ * pages that don't render an editor don't pay.
11
+ *
12
+ * Light surface kept here:
13
+ * - All public types (erased at compile time).
14
+ * - `mentionPresets` — pure data describing how to render mentions to
15
+ * markdown. No TipTap imports at module scope.
16
+ */
17
+
18
+ import { createLazyComponent, LoadingFallback } from '../../components';
19
+ import type { MarkdownEditorProps } from './MarkdownEditor';
20
+
21
+ export const LazyMarkdownEditor = createLazyComponent<MarkdownEditorProps>(
22
+ () => import('./MarkdownEditor').then((m) => ({ default: m.MarkdownEditor })),
23
+ {
24
+ displayName: 'LazyMarkdownEditor',
25
+ fallback: <LoadingFallback minHeight={140} text="Loading editor…" />,
26
+ },
27
+ );
28
+
29
+ // Light surface — pure helpers + types.
30
+ export { mentionPresets } from './mentionPresets';
31
+
32
+ export type {
33
+ MarkdownEditorProps,
34
+ MarkdownEditorHandle,
35
+ } from './MarkdownEditor';
36
+
37
+ export type {
38
+ MentionItem,
39
+ MentionConfig,
40
+ MentionAttrs,
41
+ MentionMarkdownRenderer,
42
+ } from './types';
@@ -278,6 +278,54 @@ const unsubscribe = useSpeechPrefs.subscribe((state) => {
278
278
 
279
279
  ---
280
280
 
281
+ ## Debug logger
282
+
283
+ Scoped, namespaced [consola](https://github.com/unjs/consola) wrapper that silences itself in production by default. Mirrors `getChatLogger()` in the Chat tool so both surfaces feel the same in DevTools.
284
+
285
+ ```ts
286
+ import { getSpeechLogger } from '@djangocfg/ui-tools';
287
+
288
+ const log = getSpeechLogger();
289
+ log.dictation.info('final merged', { len: 42 });
290
+ log.engine.debug('state', 'listening');
291
+ log.error.error('engine threw', err);
292
+ ```
293
+
294
+ Sub-loggers: `engine`, `dictation`, `slot`, `composer`, `mic`, `push`, `error`. `error` always emits; everything else is gated.
295
+
296
+ **Opt-in (any one is enough):**
297
+
298
+ 1. **Dev mode** — `NODE_ENV === 'development'` auto-enables everything.
299
+ 2. **Runtime toggle** — paste this in DevTools to enable without a rebuild:
300
+ ```js
301
+ localStorage.setItem('djangocfg:speech-debug', '1');
302
+ location.reload();
303
+ ```
304
+ `'0'` (or `removeItem`) turns it back off.
305
+ 3. **Explicit** — `getSpeechLogger(true)` from a host component (analogous to `<ChatRoot debug />`).
306
+
307
+ **What you'll see when on**, in order of a typical dictation session:
308
+
309
+ ```
310
+ [speech][slot] mount { supported: true, hasComposerHandle: true, … }
311
+ [speech][engine] subscribe { engineId: 'webspeech' }
312
+ [speech][engine] state 'listening'
313
+ [speech][engine] partial { len: 6, segmentId: 's1' }
314
+ [speech][composer] setValue → composer handle { len: 12 }
315
+ [speech][engine] final { len: 42, confidence: 0.91 }
316
+ [speech][dictation] final merged { len: 42, totalLen: 54 }
317
+ [speech][engine] autoStop silence detected
318
+ [speech][engine] state 'closed'
319
+ ```
320
+
321
+ If text never appears in your composer, look for:
322
+
323
+ - `[speech][slot] mount { hasComposerHandle: false, … }` → `<VoiceComposerSlot>` is outside a `<ChatProvider>` and no `value`/`onChange` props were given — text is going nowhere.
324
+ - `[speech][composer] warn setValue called but no composer handle is registered …` → the composer never called `useRegisterComposer(...)`. Built-in `<Composer>` and `MarkdownEditor` do this automatically; custom composers must opt in.
325
+ - `[speech][engine] final` arrives but no `[speech][dictation] final merged` follows → check `normaliseFinal` filtered the text (empty / whitespace only).
326
+
327
+ ---
328
+
281
329
  ## Public surface
282
330
 
283
331
  ### Hooks
@@ -1,5 +0,0 @@
1
- export { ChatRoot } from './chunk-PEKBT75W.mjs';
2
- import './chunk-HIK6BPL7.mjs';
3
- import './chunk-N2XQF2OL.mjs';
4
- //# sourceMappingURL=ChatRoot-JVR3M3H2.mjs.map
5
- //# sourceMappingURL=ChatRoot-JVR3M3H2.mjs.map
@@ -1,14 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkHPK3EWBF_cjs = require('./chunk-HPK3EWBF.cjs');
4
- require('./chunk-FIRK5CEH.cjs');
5
- require('./chunk-OLISEQHS.cjs');
6
-
7
-
8
-
9
- Object.defineProperty(exports, "ChatRoot", {
10
- enumerable: true,
11
- get: function () { return chunkHPK3EWBF_cjs.ChatRoot; }
12
- });
13
- //# sourceMappingURL=ChatRoot-LXIUBOXF.cjs.map
14
- //# sourceMappingURL=ChatRoot-LXIUBOXF.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tools/Map/context/MapContext.tsx","../src/tools/Map/styles/index.ts","../src/tools/Map/components/MapContainer.tsx"],"names":["createContext","useRef","useState","useCallback","useMemo","jsx","__name","useContext","useEffect","jsxs","Fragment","Map","cn","RotateCcw","ExternalLink"],"mappings":"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","file":"MapContainer-76YL2JXL.cjs","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"]}
@@ -1 +0,0 @@
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-7HXBI3OH.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"]}