@richpods/tiny-geojson-tool 0.1.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.
package/LICENSE.md ADDED
@@ -0,0 +1,55 @@
1
+ # Blue Oak Model License
2
+
3
+ Version 1.0.0
4
+
5
+ ## Purpose
6
+
7
+ This license gives everyone as much permission to work with
8
+ this software as possible, while protecting contributors
9
+ from liability.
10
+
11
+ ## Acceptance
12
+
13
+ In order to receive this license, you must agree to its
14
+ rules. The rules of this license are both obligations
15
+ under that agreement and conditions to your license.
16
+ You must not do anything with this software that triggers
17
+ a rule that you cannot or will not follow.
18
+
19
+ ## Copyright
20
+
21
+ Each contributor licenses you to do everything with this
22
+ software that would otherwise infringe that contributor's
23
+ copyright in it.
24
+
25
+ ## Notices
26
+
27
+ You must ensure that everyone who gets a copy of
28
+ any part of this software from you, with or without
29
+ changes, also gets the text of this license or a link to
30
+ <https://blueoakcouncil.org/license/1.0.0>.
31
+
32
+ ## Excuse
33
+
34
+ If anyone notifies you in writing that you have not
35
+ complied with [Notices](#notices), you can keep your
36
+ license by taking all practical steps to comply within 30
37
+ days after the notice. If you do not do so, your license
38
+ ends immediately.
39
+
40
+ ## Patent
41
+
42
+ Each contributor licenses you to do everything with this
43
+ software that would otherwise infringe any patent claims
44
+ they can license or become able to license.
45
+
46
+ ## Reliability
47
+
48
+ No contributor can revoke this license.
49
+
50
+ ## No Liability
51
+
52
+ ***As far as the law allows, this software comes as is,
53
+ without any warranty or condition, and no contributor
54
+ will be liable to anyone for any damages related to this
55
+ software or this license, under any kind of legal claim.***
package/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # @richpods/tiny-geojson-tool
2
+
3
+ Vue 3 component library for editing and viewing GeoJSON on a [MapLibre GL JS](https://maplibre.org/) map. Draw polygons, lines, and markers, style them with [simplestyle-spec](https://github.com/mapbox/simplestyle-spec) properties, and bind the result with `v-model`.
4
+
5
+ > [!IMPORTANT]
6
+ > The Tiny GeoJSON Tool is currently **v0.x** and subject to breaking changes prior to v1.0.0. Pin to a specific version or commit SHA if you need stability.
7
+
8
+ You can find a demo of this editor at [code.richpods.org/tiny-geojson-tool/](https://code.richpods.org/tiny-geojson-tool/)
9
+
10
+ ## Components
11
+
12
+ **`GeoJsonEditor`** — Full editing UI with a drawing toolbar, property editor, and interactive map. Supports drawing polygons, lines, and point markers, selecting and deleting features, and editing style properties (fill, stroke, marker color/size/icon).
13
+
14
+ **`GeoJsonViewer`** — Read-only map display. Renders GeoJSON features with hover popups for title/description.
15
+
16
+ ## Install
17
+
18
+ ```sh
19
+ npm install @richpods/tiny-geojson-tool maplibre-gl pmtiles
20
+ ```
21
+
22
+ Vue 3.5+, `maplibre-gl`, and `pmtiles` are peer dependencies.
23
+
24
+ ## Usage
25
+
26
+ ```vue
27
+ <script setup lang="ts">
28
+ import { ref } from "vue";
29
+ import { GeoJsonEditor } from "@richpods/tiny-geojson-tool";
30
+ import "@richpods/tiny-geojson-tool/styles";
31
+ import type { EditorFeatureCollection } from "@richpods/tiny-geojson-tool";
32
+
33
+ const geojson = ref<EditorFeatureCollection>({
34
+ type: "FeatureCollection",
35
+ features: [],
36
+ });
37
+ </script>
38
+
39
+ <template>
40
+ <GeoJsonEditor v-model="geojson" pmtilesUrl="https://example.com/tiles.pmtiles" />
41
+ </template>
42
+ ```
43
+
44
+ For read-only display:
45
+
46
+ ```vue
47
+ <GeoJsonViewer :modelValue="geojson" pmtilesUrl="https://example.com/tiles.pmtiles" />
48
+ ```
49
+
50
+ ## Props
51
+
52
+ Both components accept:
53
+
54
+ | Prop | Type | Default | Description |
55
+ |------|------|---------|-------------|
56
+ | `pmtilesUrl` | `string` | **(required)** | URL to a PMTiles archive for the base map |
57
+ | `center` | `[lng, lat]` | `[0, 20]` | Initial map center |
58
+ | `zoom` | `number` | `2` | Initial zoom level |
59
+
60
+ `GeoJsonEditor` additionally accepts:
61
+
62
+ | Prop | Type | Default | Description |
63
+ |------|------|---------|-------------|
64
+ | `modelValue` | `EditorFeatureCollection` | Empty collection | GeoJSON feature collection (v-model) |
65
+ | `pointRadius` | `number` | `10` | Radius of point features in pixels |
66
+ | `l10n` | `Partial<EditorLocale>` | English | Override UI strings for localization |
67
+
68
+ ## Drawing Tools
69
+
70
+ The editor toolbar provides six modes:
71
+
72
+ - **Select** — Click features to select and edit properties
73
+ - **Draw Point** — Click to place circle points
74
+ - **Draw Marker** — Click to place icon markers
75
+ - **Draw Line** — Click to add vertices, click near the last vertex to finish
76
+ - **Draw Polygon** — Click to add vertices, click near the first vertex to close
77
+ - **Eraser** — Click features to delete them
78
+
79
+ Right-click or press Escape to cancel drawing.
80
+
81
+ ## Style Properties
82
+
83
+ Features support [simplestyle-spec 1.1.0](https://github.com/mapbox/simplestyle-spec) properties:
84
+
85
+ - **Polygons** — `fill`, `fill-opacity`, `stroke`, `stroke-opacity`, `stroke-width`
86
+ - **Lines** — `stroke`, `stroke-opacity`, `stroke-width`
87
+ - **Points** — `fill`, `fill-opacity`, `stroke`, `stroke-opacity`, `stroke-width`
88
+ - **Markers** — `marker-color`, `marker-size` (small/medium/large), `marker-symbol`
89
+
90
+ All features support `title` and `description`. Extensions beyond the spec: `circle-radius`, `marker-label`, `marker-label-position`.
91
+
92
+ ## Localization
93
+
94
+ All user-facing strings in the editor can be overridden via the `l10n` prop. Pass a partial object — any keys you omit will use the English defaults.
95
+
96
+ ```vue
97
+ <script setup lang="ts">
98
+ import { ref } from "vue";
99
+ import { GeoJsonEditor } from "@richpods/tiny-geojson-tool";
100
+ import type { EditorLocale, EditorFeatureCollection } from "@richpods/tiny-geojson-tool";
101
+
102
+ const geojson = ref<EditorFeatureCollection>({
103
+ type: "FeatureCollection",
104
+ features: [],
105
+ });
106
+
107
+ const de: Partial<EditorLocale> = {
108
+ toolSelect: "Auswählen",
109
+ toolMarker: "Markierung",
110
+ toolLine: "Linie",
111
+ toolPolygon: "Polygon",
112
+ toolEraser: "Radierer",
113
+ propTitle: "Titel",
114
+ propDescription: "Beschreibung",
115
+ };
116
+ </script>
117
+
118
+ <template>
119
+ <GeoJsonEditor
120
+ v-model="geojson"
121
+ :l10n="de"
122
+ pmtilesUrl="https://example.com/tiles.pmtiles" />
123
+ </template>
124
+ ```
125
+
126
+ See `EditorLocale` for the full list of keys and `DEFAULT_LOCALE` for the English defaults.
127
+
128
+ ## Theming
129
+
130
+ All styles use CSS custom properties prefixed with `--tge-`. Override them to customize the look.
131
+
132
+ ## Base Map
133
+
134
+ The base map expects vector tiles served from a PMTiles archive. We recommend the [Shortbread](https://shortbread-tiles.org/) schema for your tiles. You must provide the `pmtilesUrl` prop pointing to your own tile source.
135
+
136
+ ## Development
137
+
138
+ ```sh
139
+ npm install
140
+ npm run dev # Start demo at localhost:5173
141
+ npm run build # Build library to dist/
142
+ npm run build:demo # Build demo app to dist-demo/
143
+ npm run preview:demo # Preview built demo locally
144
+ npm run typecheck # Run type checking
145
+ ```
146
+
147
+ ## Acknowledgements
148
+
149
+ This project is built with the following open-source libraries:
150
+
151
+ - **[Vue](https://vuejs.org/)** — JavaScript framework
152
+ - **[MapLibre GL JS](https://maplibre.org/)** — Open-source map rendering library
153
+ - **[PMTiles](https://github.com/protomaps/PMTiles)** — Cloud-optimized tile archive format
154
+ - **[Ionicons](https://ionic.io/ionicons)** — Open-source icon set
155
+ - **[Shortbread](https://shortbread-tiles.org/)** — Vector tile schema for OpenStreetMap data
156
+
157
+ Map data: [OpenStreetMap](https://www.openstreetmap.org/copyright) contributors.
158
+
159
+ ## License
160
+
161
+ [Blue Oak Model License 1.0.0](https://blueoakcouncil.org/license/1.0.0)
@@ -0,0 +1,22 @@
1
+ import type { EditorFeatureCollection, EditorFeature, Position, ToolMode } from "../types";
2
+ type __VLS_Props = {
3
+ modelValue: EditorFeatureCollection;
4
+ activeTool: ToolMode;
5
+ pmtilesUrl: string;
6
+ pointRadius?: number;
7
+ center?: Position;
8
+ zoom?: number;
9
+ };
10
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
11
+ "update:modelValue": (value: EditorFeatureCollection) => any;
12
+ featureClick: (feature: EditorFeature | null) => any;
13
+ featureDelete: (id: string) => any;
14
+ toolDone: (featureId: string) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
+ "onUpdate:modelValue"?: ((value: EditorFeatureCollection) => any) | undefined;
17
+ onFeatureClick?: ((feature: EditorFeature | null) => any) | undefined;
18
+ onFeatureDelete?: ((id: string) => any) | undefined;
19
+ onToolDone?: ((featureId: string) => any) | undefined;
20
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
21
+ declare const _default: typeof __VLS_export;
22
+ export default _default;
@@ -0,0 +1,13 @@
1
+ import type { ToolMode } from "../types";
2
+ import type { EditorLocale } from "../l10n";
3
+ type __VLS_Props = {
4
+ activeTool: ToolMode;
5
+ l10n: EditorLocale;
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
8
+ "update:activeTool": (tool: ToolMode) => any;
9
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
10
+ "onUpdate:activeTool"?: ((tool: ToolMode) => any) | undefined;
11
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
+ declare const _default: typeof __VLS_export;
13
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import type { EditorFeatureCollection, Position } from "../types";
2
+ import type { EditorLocale } from "../l10n";
3
+ type __VLS_Props = {
4
+ pmtilesUrl: string;
5
+ pointRadius?: number;
6
+ center?: Position;
7
+ zoom?: number;
8
+ l10n?: Partial<EditorLocale>;
9
+ };
10
+ type __VLS_ModelProps = {
11
+ modelValue?: EditorFeatureCollection;
12
+ };
13
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
14
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ "update:modelValue": (value: EditorFeatureCollection) => any;
16
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
17
+ "onUpdate:modelValue"?: ((value: EditorFeatureCollection) => any) | undefined;
18
+ }>, {
19
+ pointRadius: number;
20
+ l10n: Partial<EditorLocale>;
21
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
22
+ declare const _default: typeof __VLS_export;
23
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import type { EditorFeatureCollection, Position } from "../types";
2
+ type __VLS_Props = {
3
+ modelValue?: EditorFeatureCollection;
4
+ pmtilesUrl: string;
5
+ center?: Position;
6
+ zoom?: number;
7
+ };
8
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
9
+ modelValue: EditorFeatureCollection;
10
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
11
+ declare const _default: typeof __VLS_export;
12
+ export default _default;
@@ -0,0 +1,29 @@
1
+ import type { EditorFeature, EditorProperties } from "../types";
2
+ import type { EditorLocale } from "../l10n";
3
+ type __VLS_Props = {
4
+ feature: EditorFeature;
5
+ label: string;
6
+ expanded: boolean;
7
+ selected: boolean;
8
+ dragging: boolean;
9
+ reorderable: boolean;
10
+ l10n: EditorLocale;
11
+ iconUrls: Map<string, string>;
12
+ };
13
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
14
+ select: () => any;
15
+ delete: (id: string) => any;
16
+ dragstart: (event: DragEvent) => any;
17
+ dragend: (event: DragEvent) => any;
18
+ toggle: () => any;
19
+ update: (id: string, properties: Partial<EditorProperties>) => any;
20
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
21
+ onSelect?: (() => any) | undefined;
22
+ onDelete?: ((id: string) => any) | undefined;
23
+ onDragstart?: ((event: DragEvent) => any) | undefined;
24
+ onDragend?: ((event: DragEvent) => any) | undefined;
25
+ onToggle?: (() => any) | undefined;
26
+ onUpdate?: ((id: string, properties: Partial<EditorProperties>) => any) | undefined;
27
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
28
+ declare const _default: typeof __VLS_export;
29
+ export default _default;
@@ -0,0 +1,23 @@
1
+ import type { EditorFeature, EditorProperties } from "../types";
2
+ import type { EditorLocale } from "../l10n";
3
+ type __VLS_Props = {
4
+ features: EditorFeature[];
5
+ selectedFeatureId: string | null;
6
+ l10n: EditorLocale;
7
+ iconUrls: Map<string, string>;
8
+ };
9
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
10
+ select: (id: string) => any;
11
+ delete: (id: string) => any;
12
+ close: () => any;
13
+ update: (id: string, properties: Partial<EditorProperties>) => any;
14
+ reorder: (featureId: string, newIndex: number) => any;
15
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
16
+ onSelect?: ((id: string) => any) | undefined;
17
+ onDelete?: ((id: string) => any) | undefined;
18
+ onClose?: (() => any) | undefined;
19
+ onUpdate?: ((id: string, properties: Partial<EditorProperties>) => any) | undefined;
20
+ onReorder?: ((featureId: string, newIndex: number) => any) | undefined;
21
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
22
+ declare const _default: typeof __VLS_export;
23
+ export default _default;
@@ -0,0 +1,21 @@
1
+ import type { ToolMode, Position } from "../types";
2
+ export declare function useDrawing(): {
3
+ activeTool: import("vue").Ref<ToolMode, ToolMode>;
4
+ drawingCoords: import("vue").Ref<[number, number][], [number, number][] | Position[]>;
5
+ selectedFeatureId: import("vue").Ref<string | null, string | null>;
6
+ isDrawing: import("vue").ComputedRef<boolean>;
7
+ setTool: (tool: ToolMode) => void;
8
+ addDrawingCoord: (coord: Position) => void;
9
+ cancelDrawing: () => void;
10
+ finishDrawing: () => Position[];
11
+ selectFeature: (id: string | null) => void;
12
+ distancePx: (map: {
13
+ project: (lngLat: [number, number]) => {
14
+ x: number;
15
+ y: number;
16
+ };
17
+ }, a: Position, b: Position) => number;
18
+ getTempGeoJson: () => GeoJSON.FeatureCollection;
19
+ getTempLineGeoJson: (mousePos?: Position) => GeoJSON.FeatureCollection;
20
+ getTempVerticesGeoJson: () => GeoJSON.FeatureCollection;
21
+ };
@@ -0,0 +1,14 @@
1
+ import { type Ref } from "vue";
2
+ import type { EditorFeatureCollection, EditorFeature, EditorProperties, Position } from "../types";
3
+ export declare function useGeoJson(model: Ref<EditorFeatureCollection>): {
4
+ model: Ref<EditorFeatureCollection, EditorFeatureCollection>;
5
+ addFeature: (feature: EditorFeature) => void;
6
+ removeFeature: (id: string) => void;
7
+ updateFeature: (id: string, updater: (f: EditorFeature) => EditorFeature) => void;
8
+ updateFeatureProperties: (id: string, props: Partial<EditorProperties>) => void;
9
+ createPolygon: (coordinates: Position[][]) => EditorFeature;
10
+ createLineString: (coordinates: Position[]) => EditorFeature;
11
+ createPoint: (coordinates: Position) => EditorFeature;
12
+ createMarker: (coordinates: Position) => EditorFeature;
13
+ getFeature: (id: string) => EditorFeature | undefined;
14
+ };
@@ -0,0 +1,4 @@
1
+ import type { StyleSpecification } from "maplibre-gl";
2
+ export declare function useMapStyle(pmtilesUrl: string): {
3
+ getStyle: () => StyleSpecification;
4
+ };
@@ -0,0 +1,30 @@
1
+ import type { Position } from "./types";
2
+ export declare const DEFAULT_POINT_RADIUS = 10;
3
+ export declare const DEFAULT_CENTER: Position;
4
+ export declare const DEFAULT_ZOOM = 2;
5
+ /** Default style values (simplestyle-spec 1.1.0 defaults) */
6
+ export declare const DEFAULTS: {
7
+ readonly fill: "#555555";
8
+ readonly fillOpacity: 0.6;
9
+ readonly stroke: "#555555";
10
+ readonly strokeOpacity: 1;
11
+ readonly strokeWidth: 2;
12
+ readonly markerColor: "#7e7e7e";
13
+ readonly markerSize: "medium";
14
+ readonly circleRadius: 8;
15
+ };
16
+ /** Numeric scale factors for marker-size enum */
17
+ export declare const MARKER_SIZE_SCALE: Record<string, number>;
18
+ /** Layer IDs used for editor features */
19
+ export declare const LAYER_IDS: {
20
+ readonly fill: "editor-fill";
21
+ readonly line: "editor-line";
22
+ readonly points: "editor-points";
23
+ readonly symbols: "editor-symbols";
24
+ readonly labels: "editor-labels";
25
+ readonly vertices: "editor-vertices";
26
+ };
27
+ export declare const SOURCE_ID = "editor-geojson";
28
+ export declare const TEMP_SOURCE_ID = "drawing-temp";
29
+ export declare const TEMP_LINE_SOURCE_ID = "drawing-temp-line";
30
+ export declare const TEMP_VERTICES_SOURCE_ID = "drawing-temp-vertices";
@@ -0,0 +1,15 @@
1
+ import "maplibre-gl/dist/maplibre-gl.css";
2
+ import "./styles/theme-standard.scss";
3
+ import "./styles/editor.scss";
4
+ export { default as GeoJsonEditor } from "./components/GeoJsonEditor.vue";
5
+ export { default as GeoJsonViewer } from "./components/GeoJsonViewer.vue";
6
+ export { useGeoJson } from "./composables/useGeoJson";
7
+ export { useDrawing } from "./composables/useDrawing";
8
+ export { useMapStyle } from "./composables/useMapStyle";
9
+ export { getFeatureLayers, getFeatureLayerIds, getQueryableLayerIds, getVerticesLayer, reconcileFeatureLayers, getDrawingLayers, } from "./utils/layers";
10
+ export type { GeomType, FeatureSummary } from "./utils/layers";
11
+ export { loadIcon, loadIconsForFeatures, getIconUrl, COMMON_ICONS } from "./utils/icons";
12
+ export { DEFAULT_LOCALE } from "./l10n";
13
+ export type { EditorLocale } from "./l10n";
14
+ export { SOURCE_ID, LAYER_IDS, DEFAULTS, MARKER_SIZE_SCALE } from "./constants";
15
+ export type { EditorFeatureCollection, EditorFeature, EditorPolygonFeature, EditorLineStringFeature, EditorPointFeature, EditorMarkerFeature, EditorProperties, BaseProperties, FillStyleProperties, StrokeStyleProperties, MarkerStyleProperties, PointStyleProperties, LabelProperties, Position, ToolMode, EditorProps, ViewerProps, } from "./types";
package/dist/l10n.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ /** Locale strings for the GeoJSON editor UI */
2
+ export interface EditorLocale {
3
+ toolSelect: string;
4
+ toolPoint: string;
5
+ toolMarker: string;
6
+ toolLine: string;
7
+ toolPolygon: string;
8
+ toolEraser: string;
9
+ propTitle: string;
10
+ propDescription: string;
11
+ propFillColor: string;
12
+ propFillOpacity: string;
13
+ propStrokeColor: string;
14
+ propStrokeOpacity: string;
15
+ propStrokeWidth: string;
16
+ propCircleRadius: string;
17
+ propPointColor: string;
18
+ propMarkerColor: string;
19
+ propMarkerSize: string;
20
+ propSizeSmall: string;
21
+ propSizeMedium: string;
22
+ propSizeLarge: string;
23
+ propIcon: string;
24
+ propIconRemove: string;
25
+ propIconNone: string;
26
+ propIconSearch: string;
27
+ propIconNoResults: string;
28
+ propLabel: string;
29
+ propLabelPosition: string;
30
+ propPositionTop: string;
31
+ propPositionBottom: string;
32
+ propPositionLeft: string;
33
+ propPositionRight: string;
34
+ layerPanelTitle: string;
35
+ layerPanelEmpty: string;
36
+ layerDelete: string;
37
+ layerPoint: string;
38
+ layerMarker: string;
39
+ layerLine: string;
40
+ layerPolygon: string;
41
+ }
42
+ export declare const DEFAULT_LOCALE: EditorLocale;