mapixa 1.0.0

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 (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +276 -0
  3. package/dist/components/DrawTools/DrawCircleControl.d.ts +18 -0
  4. package/dist/components/DrawTools/DrawLineControl.d.ts +17 -0
  5. package/dist/components/DrawTools/DrawMarkerControl.d.ts +19 -0
  6. package/dist/components/DrawTools/DrawPolygonControl.d.ts +18 -0
  7. package/dist/components/DrawTools/DrawRectangleControl.d.ts +19 -0
  8. package/dist/components/DrawTools/FreeDrawControl.d.ts +8 -0
  9. package/dist/components/DrawTools/IntersectionControl.d.ts +8 -0
  10. package/dist/components/DrawTools/MapDrawTools.d.ts +9 -0
  11. package/dist/components/ExpandableBox.d.ts +11 -0
  12. package/dist/components/ExtraActionButtons.d.ts +7 -0
  13. package/dist/components/ExtraTools/CaptureAreaControl.d.ts +8 -0
  14. package/dist/components/ExtraTools/DrawRulerControl.d.ts +8 -0
  15. package/dist/components/ExtraTools/ExtraMapTools.d.ts +9 -0
  16. package/dist/components/ExtraTools/GoToControl.d.ts +7 -0
  17. package/dist/components/ExtraTools/ImageOverlayControl.d.ts +18 -0
  18. package/dist/components/LayerVisibilityControl/LayerVisibilityControl.d.ts +6 -0
  19. package/dist/components/MapControlBox.d.ts +14 -0
  20. package/dist/components/MapLibreTools.d.ts +85 -0
  21. package/dist/components/NavigationTools/CoordinateDisplay.d.ts +7 -0
  22. package/dist/components/NavigationTools/MapFlatViewEnforcer.d.ts +5 -0
  23. package/dist/components/NavigationTools/MapNavigator.d.ts +7 -0
  24. package/dist/components/NavigationTools/MapResizeHandler.d.ts +5 -0
  25. package/dist/components/NavigationTools/MapViewControl.d.ts +3 -0
  26. package/dist/components/ui/Icons.d.ts +36 -0
  27. package/dist/components/ui/Modal.d.ts +11 -0
  28. package/dist/components/ui/Popover.d.ts +10 -0
  29. package/dist/context/AccordionGroupContext.d.ts +8 -0
  30. package/dist/context/LayerVisibilityContext.d.ts +20 -0
  31. package/dist/context/MapToolContext.d.ts +32 -0
  32. package/dist/index.cjs +9311 -0
  33. package/dist/index.cjs.map +1 -0
  34. package/dist/index.d.ts +62 -0
  35. package/dist/index.js +52894 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/mapixa.css +1 -0
  38. package/dist/types/events.d.ts +32 -0
  39. package/dist/types/tools.d.ts +59 -0
  40. package/dist/utils/exportUtils.d.ts +17 -0
  41. package/dist/utils/generateMarkerSvg.d.ts +12 -0
  42. package/dist/utils/geoCalculations.d.ts +25 -0
  43. package/dist/utils/mapToolButtonStyles.d.ts +4 -0
  44. package/package.json +99 -0
@@ -0,0 +1 @@
1
+ :root{--mlt-primary: #007aff;--mlt-primary-hover: #0062cc;--mlt-bg-glass: rgba(255, 255, 255, .92);--mlt-border-glass: rgba(255, 255, 255, .4);--mlt-shadow: 0 8px 30px rgba(0, 0, 0, .12);--mlt-shadow-sm: 0 2px 8px rgba(0, 0, 0, .08);--mlt-text: #1d1d1f;--mlt-text-secondary: #86868b;--mlt-danger: #ff3b30;--mlt-danger-hover: #d72e24;--mlt-radius: 12px;--mlt-radius-sm: 8px;--mlt-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif}.mlt-panel{font-family:var(--mlt-font);background:var(--mlt-bg-glass);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid var(--mlt-border-glass);border-radius:var(--mlt-radius);box-shadow:var(--mlt-shadow);color:var(--mlt-text);box-sizing:border-box}.mlt-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:none;border-radius:var(--mlt-radius-sm);background:transparent;color:var(--mlt-text-secondary);cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);outline:none;box-sizing:border-box}.mlt-icon-btn:hover{background:#0000000f;color:var(--mlt-primary);transform:scale(1.05)}.mlt-icon-btn:active{transform:scale(.95)}.mlt-icon-btn.active{background:var(--mlt-primary);color:#fff;box-shadow:0 4px 12px #007aff59}.mlt-icon-btn.active:hover{background:var(--mlt-primary-hover);color:#fff}.mlt-icon-btn.danger{color:var(--mlt-danger)}.mlt-icon-btn.danger:hover{background:#ff3b301a;color:var(--mlt-danger-hover)}.mlt-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:7px 14px;border-radius:var(--mlt-radius-sm);font-family:var(--mlt-font);font-size:.82rem;font-weight:600;cursor:pointer;border:1px solid transparent;transition:all .2s ease;outline:none;text-decoration:none;box-sizing:border-box}.mlt-btn-primary{background:var(--mlt-primary);color:#fff}.mlt-btn-primary:hover{background:var(--mlt-primary-hover);box-shadow:0 4px 12px #007aff4d}.mlt-btn-outlined{background:transparent;border-color:#00000026;color:var(--mlt-text)}.mlt-btn-outlined:hover{background:#0000000d;border-color:#00000040}.mlt-btn-danger{background:transparent;color:var(--mlt-danger)}.mlt-btn-danger:hover{background:#ff3b3014}.mlt-btn-sm{padding:4px 8px;font-size:.74rem;border-radius:6px}.mlt-expandable-box{width:48px;display:flex;flex-direction:column;align-items:center;overflow:hidden;border-radius:var(--mlt-radius);background:var(--mlt-bg-glass);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid var(--mlt-border-glass);box-shadow:var(--mlt-shadow);box-sizing:border-box;transition:box-shadow .35s cubic-bezier(.4,0,.2,1),border-color .35s cubic-bezier(.4,0,.2,1),background-color .35s cubic-bezier(.4,0,.2,1)}.mlt-expandable-box:hover{box-shadow:0 10px 30px #00000029}.mlt-expandable-box.expanded{box-shadow:0 12px 36px #0003;border-color:#007aff40}.mlt-accordion-toggle{width:48px;height:48px;min-height:48px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;border:none;background:transparent;cursor:pointer;color:var(--mlt-text-secondary);transition:color .25s cubic-bezier(.4,0,.2,1),background-color .25s cubic-bezier(.4,0,.2,1),transform .15s ease;outline:none;flex-shrink:0}.mlt-accordion-toggle:hover{background:#0000000d;color:var(--mlt-text)}.mlt-accordion-toggle:active{transform:scale(.95)}.mlt-accordion-toggle.expanded{color:var(--mlt-primary);background:#007aff1a}.mlt-accordion-title{font-size:.55rem;font-weight:800;letter-spacing:.5px;text-transform:uppercase}.mlt-accordion-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .35s cubic-bezier(.4,0,.2,1),opacity .28s cubic-bezier(.4,0,.2,1),visibility .35s cubic-bezier(.4,0,.2,1);opacity:0;width:100%;pointer-events:none;visibility:hidden}.mlt-accordion-body.expanded{grid-template-rows:1fr;opacity:1;pointer-events:auto;visibility:visible}.mlt-accordion-inner{overflow:hidden;display:flex;flex-direction:column;align-items:center;gap:6px;padding:0 4px;box-sizing:border-box;transform:translateY(-8px);transition:transform .35s cubic-bezier(.4,0,.2,1),padding .35s cubic-bezier(.4,0,.2,1)}.mlt-accordion-body.expanded .mlt-accordion-inner{padding:6px 4px;transform:translateY(0)}.mlt-accordion-collapse-btn{transition:transform .25s cubic-bezier(.4,0,.2,1),background-color .2s ease,color .2s ease}.mlt-accordion-collapse-btn:hover{transform:translateY(-2px);background:#007aff1f!important;color:var(--mlt-primary)!important}.mlt-divider{width:60%;height:1px;background:#00000014;margin:4px 0;transition:opacity .3s ease}.mlt-modal-overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:#0006;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:10000;animation:mlt-fade-in .2s ease-out}.mlt-modal{background:var(--mlt-bg-glass);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border:1px solid var(--mlt-border-glass);border-radius:16px;box-shadow:0 20px 50px #00000040;width:90%;max-width:420px;max-height:85vh;overflow-y:auto;font-family:var(--mlt-font);color:var(--mlt-text);animation:mlt-scale-up .2s cubic-bezier(.16,1,.3,1);box-sizing:border-box}.mlt-modal-header{padding:16px 20px 12px;font-size:1.05rem;font-weight:700;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid rgba(0,0,0,.08)}.mlt-modal-body{padding:16px 20px;display:flex;flex-direction:column;gap:14px}.mlt-modal-footer{padding:12px 20px 16px;display:flex;align-items:center;justify-content:flex-end;gap:10px;border-top:1px solid rgba(0,0,0,.08)}.mlt-form-group{display:flex;flex-direction:column;gap:5px}.mlt-form-label{font-size:.75rem;font-weight:600;color:var(--mlt-text-secondary)}.mlt-input{width:100%;padding:8px 12px;font-family:var(--mlt-font);font-size:.85rem;border:1px solid rgba(0,0,0,.15);border-radius:var(--mlt-radius-sm);background:#fffc;color:var(--mlt-text);outline:none;transition:all .2s ease;box-sizing:border-box}.mlt-input:focus{border-color:var(--mlt-primary);box-shadow:0 0 0 3px #007aff26;background:#fff}.mlt-select{width:100%;padding:8px 12px;font-family:var(--mlt-font);font-size:.85rem;border:1px solid rgba(0,0,0,.15);border-radius:var(--mlt-radius-sm);background:#fffc;color:var(--mlt-text);outline:none;box-sizing:border-box}.mlt-slider{-webkit-appearance:none;width:100%;height:6px;border-radius:3px;background:#0000001a;outline:none;margin:8px 0}.mlt-slider::-webkit-slider-thumb{-webkit-appearance:none;width:18px;height:18px;border-radius:50%;background:var(--mlt-primary);cursor:pointer;box-shadow:0 2px 6px #0003;transition:transform .1s ease}.mlt-slider::-webkit-slider-thumb:hover{transform:scale(1.15)}.mlt-color-picker{height:36px;width:100%;padding:2px;border:1px solid rgba(0,0,0,.15);border-radius:var(--mlt-radius-sm);cursor:pointer;background:#fff}.mlt-popover{position:absolute;background:var(--mlt-bg-glass);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border:1px solid var(--mlt-border-glass);border-radius:var(--mlt-radius);box-shadow:var(--mlt-shadow);padding:14px;z-index:1000;font-family:var(--mlt-font);color:var(--mlt-text);box-sizing:border-box;animation:mlt-fade-in .15s ease-out}@keyframes mlt-fade-in{0%{opacity:0}to{opacity:1}}@keyframes mlt-scale-up{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}
@@ -0,0 +1,32 @@
1
+ import { ToolType, ToolMetrics } from './tools';
2
+ export interface DrawEndEvent {
3
+ id: string;
4
+ tool: ToolType;
5
+ feature: {
6
+ type: "Feature";
7
+ geometry: {
8
+ type: string;
9
+ coordinates: any;
10
+ };
11
+ properties: Record<string, any>;
12
+ };
13
+ coordinates: any;
14
+ properties: Record<string, any>;
15
+ metrics?: ToolMetrics;
16
+ raw?: any;
17
+ }
18
+ export interface DrawChangeEvent {
19
+ tool: ToolType;
20
+ action: "create" | "update" | "delete";
21
+ feature: any;
22
+ allFeatures: any[];
23
+ }
24
+ export interface DrawDeleteEvent {
25
+ id: string;
26
+ tool: ToolType;
27
+ }
28
+ export interface LayerVisibilityChangeEvent {
29
+ tool: ToolType;
30
+ visible: boolean;
31
+ visibilityState: Record<string, boolean>;
32
+ }
@@ -0,0 +1,59 @@
1
+ import { ReactNode } from 'react';
2
+ export type ToolType = "marker" | "line" | "polygon" | "circle" | "rectangle" | "freedraw" | "ruler" | "capture" | "goto" | "overlay";
3
+ export type AfterDrawMode = "modal" | "auto-save" | "callback";
4
+ export interface ToolMetrics {
5
+ distanceKm?: number;
6
+ areaSqM?: number;
7
+ areaSqKm?: number;
8
+ radiusKm?: number;
9
+ perimeterKm?: number;
10
+ pointCount?: number;
11
+ }
12
+ export interface ActionContext {
13
+ tool: ToolType;
14
+ feature?: any;
15
+ coordinates?: any;
16
+ properties?: Record<string, any>;
17
+ metrics?: ToolMetrics;
18
+ map?: any;
19
+ closeModal?: () => void;
20
+ }
21
+ export interface ExtraActionItem {
22
+ id: string;
23
+ label: string;
24
+ icon?: ReactNode;
25
+ variant?: "text" | "outlined" | "contained";
26
+ color?: "primary" | "secondary" | "success" | "error" | "info" | "warning";
27
+ tooltip?: string;
28
+ onClick: (context: ActionContext) => void | Promise<void>;
29
+ }
30
+ export interface LayerVisibilityState {
31
+ marker: boolean;
32
+ line: boolean;
33
+ polygon: boolean;
34
+ circle: boolean;
35
+ rectangle: boolean;
36
+ freedraw: boolean;
37
+ ruler: boolean;
38
+ overlay: boolean;
39
+ [key: string]: boolean;
40
+ }
41
+ export interface ToolConfig {
42
+ enabled?: boolean;
43
+ visible?: boolean;
44
+ extraActions?: ExtraActionItem[];
45
+ afterDrawMode?: AfterDrawMode;
46
+ }
47
+ export interface ToolsConfiguration {
48
+ marker?: ToolConfig;
49
+ line?: ToolConfig;
50
+ polygon?: ToolConfig;
51
+ circle?: ToolConfig;
52
+ rectangle?: ToolConfig;
53
+ freedraw?: ToolConfig;
54
+ ruler?: ToolConfig;
55
+ capture?: ToolConfig;
56
+ goto?: ToolConfig;
57
+ overlay?: ToolConfig;
58
+ [key: string]: ToolConfig | undefined;
59
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Trigger browser download of a GeoJSON object as a .geojson or .json file
3
+ */
4
+ export declare function downloadGeoJSON(data: any, filename?: string): void;
5
+ /**
6
+ * Copy string / JSON representation to clipboard
7
+ */
8
+ export declare function copyToClipboard(text: string): Promise<boolean>;
9
+ /**
10
+ * Export canvas portion as a downloadable PNG image
11
+ */
12
+ export declare function downloadCanvasArea(canvas: HTMLCanvasElement, rect: {
13
+ x: number;
14
+ y: number;
15
+ width: number;
16
+ height: number;
17
+ }, filename?: string): Promise<string>;
@@ -0,0 +1,12 @@
1
+ export interface MarkerSvgConfig {
2
+ size: number;
3
+ opacity: number;
4
+ markerColor: string;
5
+ iconType: "star" | "circle" | "square" | "pin";
6
+ iconColor: string;
7
+ }
8
+ /**
9
+ * Generate valid SVG string for a modern map pin marker
10
+ */
11
+ export declare function generateMarkerSvg(m: MarkerSvgConfig): string;
12
+ export default generateMarkerSvg;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Calculate Great Circle distance between two points [lon, lat] using Haversine formula.
3
+ * Returns distance in kilometers.
4
+ */
5
+ export declare function calculateDistanceKm(p1: [number, number], p2: [number, number]): number;
6
+ /**
7
+ * Calculate total path distance for a line coordinate array [[lon, lat], ...]
8
+ */
9
+ export declare function calculateLineDistanceKm(coordinates: number[][]): number;
10
+ /**
11
+ * Approximate spherical polygon area in square meters.
12
+ */
13
+ export declare function calculatePolygonAreaSqM(coordinates: number[][]): number;
14
+ /**
15
+ * Generate a GeoJSON Polygon circle approximating given center [lon, lat] and radius in km.
16
+ */
17
+ export declare function createGeoJSONCircle(center: [number, number], radiusInKm: number, points?: number): number[][];
18
+ /**
19
+ * Midpoint between two coordinates
20
+ */
21
+ export declare function getMidpoint(pt1: [number, number], pt2: [number, number]): [number, number];
22
+ /**
23
+ * Line segment intersection check
24
+ */
25
+ export declare function getLineIntersection(p1: [number, number], p2: [number, number], p3: [number, number], p4: [number, number]): [number, number] | null;
@@ -0,0 +1,4 @@
1
+ import { CSSProperties } from 'react';
2
+ export declare const getMapToolButtonStyle: (isActive: boolean, size?: number) => CSSProperties;
3
+ export declare const getMapToolButtonSx: (isActive: boolean, size?: number) => CSSProperties;
4
+ export declare const getMapToolAccordionButtonSx: (isActive: boolean, size?: number) => CSSProperties;
package/package.json ADDED
@@ -0,0 +1,99 @@
1
+ {
2
+ "name": "mapixa",
3
+ "version": "1.0.0",
4
+ "description": "A feature-rich, extensible suite of drawing, measurement, navigation, and layer visibility tools for MapLibre GL JS & React.",
5
+ "keywords": [
6
+ "mapixa",
7
+ "maplibre",
8
+ "maplibre-gl",
9
+ "react-map-gl",
10
+ "map-tools",
11
+ "draw-tools",
12
+ "gis",
13
+ "measure",
14
+ "ruler",
15
+ "polygon",
16
+ "marker",
17
+ "geojson"
18
+ ],
19
+ "author": "Seyed Ali Rafazi",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/seyedali-rafazi/Mapixa.git"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/seyedali-rafazi/Mapixa/issues"
27
+ },
28
+ "homepage": "https://github.com/seyedali-rafazi/Mapixa#readme",
29
+ "type": "module",
30
+ "main": "./dist/index.cjs",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js",
37
+ "require": "./dist/index.cjs"
38
+ },
39
+ "./style.css": "./dist/mapixa.css",
40
+ "./mapixa.css": "./dist/mapixa.css",
41
+ "./dist/style.css": "./dist/mapixa.css",
42
+ "./dist/mapixa.css": "./dist/mapixa.css",
43
+ "./dist/maplibre-gl-tools.css": "./dist/mapixa.css",
44
+ "./package.json": "./package.json"
45
+ },
46
+ "files": [
47
+ "dist",
48
+ "README.md",
49
+ "LICENSE"
50
+ ],
51
+ "scripts": {
52
+ "dev": "vite",
53
+ "build": "vite build --mode lib",
54
+ "build:lib": "vite build --mode lib",
55
+ "build:demo": "vite build --mode demo",
56
+ "prepublishOnly": "npm run build:lib",
57
+ "preview": "vite preview",
58
+ "lint": "eslint ."
59
+ },
60
+ "peerDependencies": {
61
+ "maplibre-gl": "^3.0.0 || ^4.0.0 || ^5.0.0",
62
+ "react": "^18.0.0 || ^19.0.0",
63
+ "react-dom": "^18.0.0 || ^19.0.0"
64
+ },
65
+ "peerDependenciesMeta": {
66
+ "maplibre-gl": {
67
+ "optional": false
68
+ },
69
+ "react": {
70
+ "optional": false
71
+ },
72
+ "react-dom": {
73
+ "optional": false
74
+ }
75
+ },
76
+ "dependencies": {
77
+ "lucide-react": "^1.47.0",
78
+ "react-map-gl": "^8.1.0",
79
+ "sonner": "^2.0.7"
80
+ },
81
+ "devDependencies": {
82
+ "@eslint/js": "^9.24.0",
83
+ "@types/node": "^22.0.0",
84
+ "@types/react": "^19.1.1",
85
+ "@types/react-dom": "^19.1.2",
86
+ "@vitejs/plugin-react": "^4.3.4",
87
+ "eslint": "^9.24.0",
88
+ "eslint-plugin-react": "^7.37.5",
89
+ "eslint-plugin-react-hooks": "^5.2.0",
90
+ "eslint-plugin-react-refresh": "^0.4.19",
91
+ "globals": "^16.0.0",
92
+ "maplibre-gl": "^5.1.0",
93
+ "react": "^19.1.0",
94
+ "react-dom": "^19.1.0",
95
+ "typescript": "^5.4.5",
96
+ "vite": "^6.2.6",
97
+ "vite-plugin-dts": "^4.5.3"
98
+ }
99
+ }