@versatiles/svelte 0.3.0 → 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 (47) hide show
  1. package/README.md +11 -6
  2. package/dist/components/BBoxMap/AutoComplete.svelte +176 -0
  3. package/dist/components/{AutoComplete.svelte.d.ts → BBoxMap/AutoComplete.svelte.d.ts} +12 -18
  4. package/dist/components/BBoxMap/BBoxMap.svelte +43 -54
  5. package/dist/components/BBoxMap/BBoxMap.svelte.d.ts +4 -17
  6. package/dist/components/BasicMap/BasicMap.svelte +34 -37
  7. package/dist/components/BasicMap/BasicMap.svelte.d.ts +9 -24
  8. package/dist/components/LocatorMap/LocatorMap.svelte +61 -20
  9. package/dist/components/MapEditor/Editor.svelte +25 -0
  10. package/dist/components/MapEditor/Editor.svelte.d.ts +7 -0
  11. package/dist/components/MapEditor/EditorLine.svelte +27 -0
  12. package/dist/components/MapEditor/EditorLine.svelte.d.ts +7 -0
  13. package/dist/components/MapEditor/EditorMarker.svelte +42 -0
  14. package/dist/components/MapEditor/EditorMarker.svelte.d.ts +7 -0
  15. package/dist/components/MapEditor/MapEditor.svelte +99 -0
  16. package/dist/components/MapEditor/MapEditor.svelte.d.ts +4 -0
  17. package/dist/components/MapEditor/editor.scss +16 -0
  18. package/dist/components/MapEditor/lib/element_abstract.d.ts +20 -0
  19. package/dist/components/MapEditor/lib/element_abstract.js +58 -0
  20. package/dist/components/MapEditor/lib/element_line.d.ts +14 -0
  21. package/dist/components/MapEditor/lib/element_line.js +76 -0
  22. package/dist/components/MapEditor/lib/element_marker.d.ts +20 -0
  23. package/dist/components/MapEditor/lib/element_marker.js +191 -0
  24. package/dist/components/MapEditor/lib/geocoder.d.ts +1 -0
  25. package/dist/components/MapEditor/lib/geocoder.js +8 -0
  26. package/dist/components/MapEditor/lib/geometry_manager.d.ts +18 -0
  27. package/dist/components/MapEditor/lib/geometry_manager.js +117 -0
  28. package/dist/components/MapEditor/lib/map_layer.d.ts +14 -0
  29. package/dist/components/MapEditor/lib/map_layer.js +61 -0
  30. package/dist/components/MapEditor/lib/types.d.ts +112 -0
  31. package/dist/components/MapEditor/lib/types.js +1 -0
  32. package/dist/components/MapEditor/lib/utils.d.ts +2 -0
  33. package/dist/components/MapEditor/lib/utils.js +11 -0
  34. package/dist/index.d.ts +2 -1
  35. package/dist/index.js +2 -1
  36. package/dist/utils/draw/bbox.d.ts +2 -9
  37. package/dist/utils/draw/bbox.js +8 -13
  38. package/dist/utils/map_style.d.ts +5 -2
  39. package/dist/utils/map_style.js +13 -6
  40. package/package.json +9 -6
  41. package/dist/components/AutoComplete.svelte +0 -196
  42. package/dist/utils/draw/abstract.d.ts +0 -5
  43. package/dist/utils/draw/abstract.js +0 -2
  44. package/dist/utils/draw/marker.d.ts +0 -24
  45. package/dist/utils/draw/marker.js +0 -97
  46. package/dist/utils/draw/style.d.ts +0 -19
  47. package/dist/utils/draw/style.js +0 -40
@@ -1,196 +0,0 @@
1
- <!-- AutoComplete.svelte -->
2
- <script lang="ts" generics="T">
3
- import { isDarkMode } from '../utils/map_style.js';
4
- /* eslint svelte/no-at-html-tags: off */
5
-
6
- import { createEventDispatcher, onMount } from 'svelte';
7
- const dispatch = createEventDispatcher();
8
-
9
- type Item = { key: string; value: T };
10
- type ResultItem = Item & { _label: string };
11
-
12
- // Component properties
13
- export let placeholder: string = '';
14
- export let minChar: number = 3;
15
- export let maxItems: number = 10;
16
-
17
- // Reactive variables
18
- export let items: Item[];
19
-
20
- let inputElement: HTMLInputElement; // Reference to DOM element
21
- let autocompleteElement: HTMLDivElement; // Reference to DOM element
22
- let isOpen = false;
23
- let results: ResultItem[] = [];
24
- let selectedIndex = 0;
25
- let inputText: string = '';
26
-
27
- // Escape special characters in search string for use in regex
28
- const regExpEscape = (s: string) => s.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
29
-
30
- if (inputText.length >= minChar) {
31
- const r = filterResults();
32
- if (r.length > 0) {
33
- const { key, value } = r[0];
34
- inputText = key;
35
- dispatch('change', JSON.parse(JSON.stringify(value)));
36
- } else {
37
- inputText = '';
38
- }
39
- }
40
-
41
- export function setInputText(text: string) {
42
- inputText = text;
43
- results = filterResults();
44
- close(0);
45
- }
46
-
47
- // Handle input change
48
- function onChange() {
49
- if (inputText.length >= minChar) {
50
- results = filterResults();
51
- selectedIndex = 0;
52
- isOpen = true;
53
- } else {
54
- isOpen = false;
55
- }
56
- }
57
-
58
- function onFocus() {
59
- inputElement.setSelectionRange(0, 1000);
60
- }
61
-
62
- // Filter results based on search query
63
- function filterResults(): ResultItem[] {
64
- const searchText = inputText.trim();
65
- const searchTextUpper = searchText.toUpperCase();
66
- const searchReg = RegExp(regExpEscape(searchText), 'i');
67
- return items
68
- .filter((item) => item.key.toUpperCase().includes(searchTextUpper))
69
- .slice(0, maxItems)
70
- .map((item) => ({
71
- ...item,
72
- _label: item.key.replace(searchReg, '<span>$&</span>')
73
- }));
74
- }
75
-
76
- // Handle keyboard navigation
77
- function onKeyDown(event: KeyboardEvent) {
78
- switch (event.key) {
79
- case 'ArrowDown':
80
- if (selectedIndex < results.length - 1) selectedIndex += 1;
81
- break;
82
- case 'ArrowUp':
83
- if (selectedIndex > 0) selectedIndex -= 1;
84
- break;
85
- case 'Enter':
86
- event.preventDefault();
87
- close(selectedIndex);
88
- break;
89
- case 'Escape':
90
- event.preventDefault();
91
- close();
92
- break;
93
- }
94
- }
95
-
96
- // Close the autocomplete and select an item
97
- function close(index = -1) {
98
- isOpen = false;
99
- if (index >= 0 && results[index]) {
100
- const { key, value } = results[index];
101
- inputText = key;
102
- dispatch('change', JSON.parse(JSON.stringify(value)));
103
- }
104
- }
105
-
106
- onMount(() => {
107
- const darkMode = isDarkMode(autocompleteElement);
108
- autocompleteElement.style.setProperty('--bg-color', darkMode ? '#000' : '#fff');
109
- autocompleteElement.style.setProperty('--fg-color', darkMode ? '#fff' : '#000');
110
- });
111
- </script>
112
-
113
- <svelte:window on:click={() => close()} />
114
-
115
- <div class="autocomplete" bind:this={autocompleteElement}>
116
- <input
117
- type="text"
118
- bind:value={inputText}
119
- {placeholder}
120
- autocomplete="off"
121
- on:input={onChange}
122
- on:keydown={onKeyDown}
123
- on:focusin={onFocus}
124
- on:click={(e) => e.stopPropagation()}
125
- bind:this={inputElement}
126
- aria-activedescendant={isOpen ? `result-${selectedIndex}` : undefined}
127
- aria-autocomplete="list"
128
- aria-controls="autocomplete-results"
129
- />
130
- <div class="autocomplete-results" class:hide-results={!isOpen}>
131
- {#each results as result, i}
132
- <button
133
- on:click={() => close(i)}
134
- class={i === selectedIndex ? ' is-active' : ''}
135
- role="option"
136
- aria-selected={i === selectedIndex}
137
- >
138
- {@html result._label}
139
- </button>
140
- {/each}
141
- </div>
142
- </div>
143
-
144
- <style>
145
- .autocomplete {
146
- position: relative;
147
- border-radius: 0.5em;
148
- background: color-mix(in srgb, var(--bg-color) 80%, transparent);
149
- box-sizing: border-box;
150
- line-height: normal;
151
- }
152
-
153
- input {
154
- width: 100%;
155
- display: block;
156
- box-sizing: border-box;
157
- padding: 0.3em 0.6em;
158
- border: none;
159
- background: none;
160
- color: var(--fg-color);
161
- }
162
-
163
- .autocomplete-results {
164
- padding: 0;
165
- margin: 0;
166
- background: none;
167
- width: 100%;
168
- display: block;
169
- border-radius: 0 0 0.5em 0.5em;
170
- }
171
-
172
- .autocomplete-results.hide-results {
173
- display: none;
174
- }
175
-
176
- button {
177
- padding: 0.2rem 0.5rem;
178
- cursor: pointer;
179
- border: none;
180
- display: block;
181
- background: transparent;
182
- font-weight: normal;
183
- color: color-mix(in srgb, var(--fg-color) 50%, transparent);
184
- width: 100%;
185
- text-align: left;
186
- }
187
-
188
- button > :global(span) {
189
- color: var(--fg-color);
190
- }
191
-
192
- button.is-active,
193
- button:hover {
194
- background-color: color-mix(in srgb, var(--fg-color) 15%, transparent);
195
- }
196
- </style>
@@ -1,5 +0,0 @@
1
- import type { LngLatBounds } from 'maplibre-gl';
2
- export declare abstract class AbstractDrawer<Geometry> {
3
- abstract setGeometry(geometry: Geometry): void;
4
- abstract getBounds(): LngLatBounds;
5
- }
@@ -1,2 +0,0 @@
1
- export class AbstractDrawer {
2
- }
@@ -1,24 +0,0 @@
1
- import type geojson from 'geojson';
2
- import type { SymbolStyle } from './style.js';
3
- import { AbstractDrawer } from './abstract.js';
4
- export type Point = [number, number];
5
- export declare class MarkerDrawer extends AbstractDrawer<geojson.BBox> {
6
- private source?;
7
- private isDragging;
8
- private dragPoint;
9
- private map;
10
- private canvas;
11
- private symbolStyle;
12
- private point;
13
- constructor(map: maplibregl.Map, options?: {
14
- point?: Point;
15
- } & SymbolStyle);
16
- private updateDragPoint;
17
- private getAsFeatureCollection;
18
- setGeometry(point: geojson.Position): void;
19
- getBounds(): maplibregl.LngLatBounds;
20
- private redraw;
21
- private getAsPixel;
22
- private checkDragPointAt;
23
- private doDrag;
24
- }
@@ -1,97 +0,0 @@
1
- import { AbstractDrawer } from './abstract.js';
2
- import { getSymbolStyle } from './style.js';
3
- const maplibregl = await import('maplibre-gl');
4
- const { LngLatBounds } = maplibregl;
5
- export class MarkerDrawer extends AbstractDrawer {
6
- source;
7
- isDragging = false;
8
- dragPoint = false;
9
- map;
10
- canvas;
11
- symbolStyle;
12
- point;
13
- constructor(map, options) {
14
- super();
15
- this.point = options?.point ?? [0, 0];
16
- this.symbolStyle = getSymbolStyle(options);
17
- this.map = map;
18
- const sourceId = 'marker_' + Math.random().toString(36).slice(2);
19
- if (this.source)
20
- throw new Error('BBoxDrawer already added to map');
21
- map.addSource(sourceId, { type: 'geojson', data: this.getAsFeatureCollection() });
22
- map.addLayer({
23
- id: 'marker_' + Math.random().toString(36).slice(2),
24
- type: 'symbol',
25
- source: sourceId,
26
- filter: ['==', '$type', 'Point'],
27
- ...this.symbolStyle
28
- });
29
- this.source = map.getSource(sourceId);
30
- this.canvas = map.getCanvasContainer();
31
- map.on('mousemove', (e) => {
32
- if (e.originalEvent.buttons % 2 === 0)
33
- return this.checkDragPointAt(e.point);
34
- if (!this.isDragging)
35
- return;
36
- if (!this.dragPoint)
37
- return this.checkDragPointAt(e.point);
38
- this.doDrag(e.lngLat);
39
- this.redraw();
40
- e.preventDefault();
41
- });
42
- map.on('mousedown', (e) => {
43
- if (this.isDragging)
44
- return;
45
- if (e.originalEvent.buttons % 2) {
46
- this.checkDragPointAt(e.point);
47
- if (this.dragPoint)
48
- this.isDragging = true;
49
- if (this.isDragging)
50
- e.preventDefault();
51
- }
52
- });
53
- map.on('mouseup', () => {
54
- this.isDragging = false;
55
- this.updateDragPoint(false);
56
- });
57
- }
58
- updateDragPoint(dragPoint) {
59
- if (this.dragPoint === dragPoint)
60
- return;
61
- this.dragPoint = dragPoint;
62
- this.canvas.style.cursor = dragPoint ? 'move' : 'default';
63
- }
64
- getAsFeatureCollection() {
65
- return {
66
- type: 'FeatureCollection',
67
- features: [getPoint(this.point)]
68
- };
69
- function getPoint(coordinates) {
70
- return { type: 'Feature', geometry: { type: 'Point', coordinates }, properties: {} };
71
- }
72
- }
73
- setGeometry(point) {
74
- this.point = [point[0], point[1]];
75
- this.redraw();
76
- }
77
- getBounds() {
78
- return new LngLatBounds(this.point, this.point);
79
- }
80
- redraw() {
81
- this.source?.setData(this.getAsFeatureCollection());
82
- }
83
- getAsPixel() {
84
- const p = this.map.project([this.point[0], this.point[1]]);
85
- return [p.x, p.y];
86
- }
87
- checkDragPointAt(point) {
88
- const maxDistance = 5;
89
- const { x, y } = point;
90
- const [x0, y0] = this.getAsPixel();
91
- const distance = Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2));
92
- this.updateDragPoint(distance < maxDistance);
93
- }
94
- doDrag(lngLat) {
95
- this.point = [Math.round(lngLat.lng * 1e5) / 1e5, Math.round(lngLat.lat * 1e5) / 1e5];
96
- }
97
- }
@@ -1,19 +0,0 @@
1
- import type { FillLayerSpecification, LineLayerSpecification, SymbolLayerSpecification } from 'maplibre-gl';
2
- export type AbstractLayerStyle<T extends FillLayerSpecification | LineLayerSpecification | SymbolLayerSpecification> = {
3
- paint: {} & T['paint'];
4
- layout: {} & T['layout'];
5
- };
6
- export interface FillStyle {
7
- color?: string;
8
- fillColor?: string;
9
- }
10
- export declare function getFillStyle(style?: FillStyle): AbstractLayerStyle<FillLayerSpecification>;
11
- export interface LineStyle {
12
- color?: string;
13
- lineColor?: string;
14
- }
15
- export declare function getLineStyle(style?: LineStyle): AbstractLayerStyle<LineLayerSpecification>;
16
- export interface SymbolStyle {
17
- color?: string;
18
- }
19
- export declare function getSymbolStyle(style?: SymbolStyle): AbstractLayerStyle<SymbolLayerSpecification>;
@@ -1,40 +0,0 @@
1
- import { Color } from '@versatiles/style';
2
- export function getFillStyle(style) {
3
- const result = {
4
- layout: {},
5
- paint: {}
6
- };
7
- if (style) {
8
- if (style.fillColor) {
9
- result.paint['fill-color'] = Color.parse(style.fillColor).asString();
10
- }
11
- else if (style.color) {
12
- result.paint['fill-color'] = Color.parse(style.color).fade(0.8).asString();
13
- }
14
- }
15
- return result;
16
- }
17
- export function getLineStyle(style) {
18
- const result = {
19
- layout: { 'line-cap': 'round', 'line-join': 'round' },
20
- paint: {}
21
- };
22
- if (style) {
23
- const color = style.lineColor ?? style.color;
24
- if (color)
25
- result.paint['line-color'] = Color.parse(color).asString();
26
- }
27
- return result;
28
- }
29
- export function getSymbolStyle(style) {
30
- const result = {
31
- layout: {},
32
- paint: {}
33
- };
34
- result.paint['icon-color'] = Color.parse(style?.color ?? '#a00').asString();
35
- result.paint['icon-halo-color'] = Color.parse('#fff').asString();
36
- result.paint['icon-halo-width'] = 0.5;
37
- result.paint['icon-halo-blur'] = 0;
38
- result.layout['icon-image'] = 'basics:icon-embassy';
39
- return result;
40
- }