Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions docs/content/scripts/maplibre/2.api/10.attribution-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: <ScriptMapLibreAttributionControl>
---

Moves or restyles the map's attribution. Use it to change the attribution position, force compact mode, or add your own credits.

```vue
<template>
<ScriptMapLibreMap map-style="https://tiles.openfreemap.org/styles/liberty" :center="[147.33, -42.88]">
<ScriptMapLibreAttributionControl
position="bottom-left"
:options="{ compact: false, customAttribution: 'Data: Hobart City Council' }"
/>
</ScriptMapLibreMap>
</template>
```

::callout{color="amber"}
Most tile providers require attribution. OpenFreeMap and OpenStreetMap require it. Keep an attribution control on every map that shows their tiles.
::

## How it works with the default attribution

MapLibre adds an attribution control to every map by default. Two controls would show the attribution twice. This component prevents that:

- When the component mounts, it removes the map's attribution control and adds its own.
- When the component unmounts, it adds the map's control back. This also happens if your code removed the component's control first.

The map therefore shows attribution exactly once. Unmounting the component does not remove the default attribution.

If you set `attributionControl: false` in the map `options`, the map has no control to restore. The component then adds its own control, and unmounting removes it.

Use one `<ScriptMapLibreAttributionControl>`{lang="html"} per map. The map's control returns to its default position, bottom-right, when the component unmounts.

## Attribution text

The control always shows the attribution from the style sources, for example OpenFreeMap and OpenStreetMap. `options` cannot remove it.

The component `options` override the options of the map's attribution control. Options you omit keep the map's values.

If you omit `options.customAttribution`, the credits from the map's control stay, including MapLibre's default "MapLibre" link. If you set it, your value replaces them.

`new maplibregl.AttributionControl()`{lang="ts"} reads `options` and `position` once, when it creates the control. To apply a change, change the component `key`.

::script-types{script-key="maplibre" filter="ScriptMapLibreAttributionControl"}
::
18 changes: 18 additions & 0 deletions docs/content/scripts/maplibre/2.api/7.scale-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: <ScriptMapLibreScaleControl>
---

Adds MapLibre's scale bar to the nearest parent map. MapLibre places it in the bottom-left corner by default.

```vue
<template>
<ScriptMapLibreMap map-style="https://tiles.openfreemap.org/styles/liberty" :center="[147.33, -42.88]">
<ScriptMapLibreScaleControl position="bottom-left" :options="{ unit: 'metric', maxWidth: 120 }" />
</ScriptMapLibreMap>
</template>
```

`new maplibregl.ScaleControl()`{lang="ts"} reads `options` and `position` once, when it creates the control. `options.unit` also updates reactively through `setUnit()`{lang="ts"}. To apply any other change, change the component `key`.

::script-types{script-key="maplibre" filter="ScriptMapLibreScaleControl"}
::
58 changes: 58 additions & 0 deletions docs/content/scripts/maplibre/2.api/8.geolocate-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: <ScriptMapLibreGeolocateControl>
---

Adds MapLibre's geolocate button to the nearest parent map. The button asks the browser for the user's location and moves the camera there.

```vue
<script setup lang="ts">
import type { ScriptMapLibreGeolocateControlEmits } from '@nuxt/scripts'

const message = ref('')

function onError(event: ScriptMapLibreGeolocateControlEmits['error'][0]) {
message.value = event.code === 1 ? 'Location permission denied.' : event.message
}
</script>

<template>
<ScriptMapLibreMap map-style="https://tiles.openfreemap.org/styles/liberty" :center="[147.33, -42.88]">
<ScriptMapLibreGeolocateControl
position="top-left"
:options="{ trackUserLocation: true }"
@error="onError"
@unavailable="message = 'Location is not available in this browser.'"
/>
</ScriptMapLibreMap>
<p role="status">
{{ message }}
</p>
</template>
```

`new maplibregl.GeolocateControl()`{lang="ts"} reads `options` and `position` once, when it creates the control. To apply a change, change the component `key`.

The component exposes the MapLibre control as `control`. Call `control.value.trigger()`{lang="ts"} to request the location from code.

## Events

The component emits every `GeolocateControl` event with MapLibre's event object:

- `geolocate` fires when the browser returns a position.
- `error` fires when the browser returns an error.
- `outofmaxbounds` fires when the position is outside the map's `maxBounds`.
- `trackuserlocationstart` and `trackuserlocationend` fire when tracking starts and stops. They need `trackUserLocation`.
- `userlocationfocus` and `userlocationlostfocus` fire when the camera locks to or leaves the user's location.

## Permission denied

Geolocation can fail in two ways. The component reports both.

- If the user denies the permission prompt, `error` fires with `code` 1. MapLibre then disables the button.
- If the permission was already denied when the control loaded, MapLibre disables the button and fires no event. The component emits `unavailable` with `'permission-denied'`.
- If the browser has no Geolocation API, the component emits `unavailable` with `'unsupported'`.

Geolocation needs a secure context. On a plain HTTP origin other than `localhost`, the browser denies it.

::script-types{script-key="maplibre" filter="ScriptMapLibreGeolocateControl"}
::
24 changes: 24 additions & 0 deletions docs/content/scripts/maplibre/2.api/9.fullscreen-control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: <ScriptMapLibreFullscreenControl>
---

Adds MapLibre's fullscreen button to the nearest parent map. The map container goes fullscreen by default. Pass `options.container` to make a different element fullscreen.

```vue
<template>
<ScriptMapLibreMap map-style="https://tiles.openfreemap.org/styles/liberty" :center="[147.33, -42.88]">
<ScriptMapLibreFullscreenControl
position="top-right"
@fullscreenstart="console.log('fullscreen')"
@fullscreenend="console.log('windowed')"
/>
</ScriptMapLibreMap>
</template>
```

`new maplibregl.FullscreenControl()`{lang="ts"} reads `options` and `position` once, when it creates the control. To apply a change, change the component `key`.

If the browser has no Fullscreen API, or `options.pseudo` is `true`, MapLibre expands the map with CSS instead.

::script-types{script-key="maplibre" filter="ScriptMapLibreFullscreenControl"}
::
4 changes: 4 additions & 0 deletions docs/content/scripts/maplibre/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ OpenFreeMap's public instance needs no API key, but it has no SLA. Read [Styles
- [`<ScriptMapLibreMarker>`{lang="html"}](/scripts/maplibre/api/marker) adds an accessible, reactive marker.
- [`<ScriptMapLibrePopup>`{lang="html"}](/scripts/maplibre/api/popup) binds slotted HTML to a marker or coordinate.
- [`<ScriptMapLibreNavigationControl>`{lang="html"}](/scripts/maplibre/api/navigation-control) adds zoom, compass, and pitch controls.
- [`<ScriptMapLibreScaleControl>`{lang="html"}](/scripts/maplibre/api/scale-control) adds a scale bar.
- [`<ScriptMapLibreGeolocateControl>`{lang="html"}](/scripts/maplibre/api/geolocate-control) finds the user's location.
- [`<ScriptMapLibreFullscreenControl>`{lang="html"}](/scripts/maplibre/api/fullscreen-control) toggles fullscreen mode.
- [`<ScriptMapLibreAttributionControl>`{lang="html"}](/scripts/maplibre/api/attribution-control) moves or restyles the map attribution.
- [`<ScriptMapLibreGeoJson>`{lang="html"}](/scripts/maplibre/api/geojson) manages a GeoJSON source and its style layers, including [clustering](/scripts/maplibre/api/geojson#clustering).

## Guides
Expand Down
12 changes: 12 additions & 0 deletions packages/script/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
import type { NormalizedRegistryEntry } from './normalize'
import type { ProxyAliasConfig } from './proxy-alias'
import type {
ScriptMapLibreAttributionControlProps,
ScriptMapLibreFullscreenControlEmits,
ScriptMapLibreFullscreenControlProps,
ScriptMapLibreGeoJsonEmits,
ScriptMapLibreGeoJsonLayer,
ScriptMapLibreGeoJsonProps,
ScriptMapLibreGeoJsonResource,
ScriptMapLibreGeolocateControlEmits,
ScriptMapLibreGeolocateControlProps,
ScriptMapLibreMapEmits,
ScriptMapLibreMapExpose,
ScriptMapLibreMapProps,
Expand All @@ -16,6 +21,7 @@
ScriptMapLibreNavigationControlProps,
ScriptMapLibrePopupEmits,
ScriptMapLibrePopupProps,
ScriptMapLibreScaleControlProps,
} from './runtime/components/MapLibre/types'
import type { ProxyPrivacyInput } from './runtime/server/utils/privacy'
import type {
Expand Down Expand Up @@ -63,10 +69,15 @@
export type { FirstPartyPrivacy }

export type {
ScriptMapLibreAttributionControlProps,
ScriptMapLibreFullscreenControlEmits,
ScriptMapLibreFullscreenControlProps,
ScriptMapLibreGeoJsonEmits,
ScriptMapLibreGeoJsonLayer,
ScriptMapLibreGeoJsonProps,
ScriptMapLibreGeoJsonResource,
ScriptMapLibreGeolocateControlEmits,
ScriptMapLibreGeolocateControlProps,
ScriptMapLibreMapEmits,
ScriptMapLibreMapExpose,
ScriptMapLibreMapProps,
Expand All @@ -76,6 +87,7 @@
ScriptMapLibreNavigationControlProps,
ScriptMapLibrePopupEmits,
ScriptMapLibrePopupProps,
ScriptMapLibreScaleControlProps,
}

const UPPER_RE = /([A-Z])/g
Expand Down Expand Up @@ -573,7 +585,7 @@
// imported by runtime composables. Every snippet is always exported (empty
// until its registry entry is configured) so the static import always
// resolves, even when the related script isn't registered.
const snippets: Record<string, () => string | Promise<string>> = {

Check warning on line 588 in packages/script/src/module.ts

View workflow job for this annotation

GitHub Actions / lint

Annotating with `Record<string, () => string | Promise<string>>` discards the object's known keys. Use `satisfies` to keep them
async speedcurveLuxSnippet() {
if (!config.registry?.speedcurve)
return ''
Expand Down
136 changes: 136 additions & 0 deletions packages/script/src/registry-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,21 @@
"kind": "interface",
"code": "export interface MapLibreApi {\n maplibregl: typeof MapLibre\n}"
},
{
"name": "ScriptMapLibreAttributionControlProps",
"kind": "interface",
"code": "interface ScriptMapLibreAttributionControlProps {\n /** Position of the attribution control. MapLibre places it bottom-right by default. */\n position?: MapLibre.ControlPosition\n /**\n * Options passed to `new maplibregl.AttributionControl()`.\n * Source attribution from the style and tiles always shows. `customAttribution` only adds text.\n */\n options?: MapLibre.AttributionControlOptions\n}"
},
{
"name": "ScriptMapLibreFullscreenControlProps",
"kind": "interface",
"code": "interface ScriptMapLibreFullscreenControlProps {\n /** Position of the fullscreen control. */\n position?: MapLibre.ControlPosition\n /** Options passed to `new maplibregl.FullscreenControl()`. */\n options?: MapLibre.FullscreenControlOptions\n}"
},
{
"name": "ScriptMapLibreFullscreenControlEvents",
"kind": "interface",
"code": "interface ScriptMapLibreFullscreenControlEvents {\n fullscreenstart: MapLibre.FullscreenControlEventType['fullscreenstart']\n fullscreenend: MapLibre.FullscreenControlEventType['fullscreenend']\n}"
},
{
"name": "ScriptMapLibreGeoJsonProps",
"kind": "interface",
Expand All @@ -849,6 +864,16 @@
"kind": "interface",
"code": "interface ScriptMapLibreGeoJsonEvents {\n error: Error\n click: MapLibre.MapLayerMouseEvent\n dblclick: MapLibre.MapLayerMouseEvent\n mouseenter: MapLibre.MapLayerMouseEvent\n mousemove: MapLibre.MapLayerMouseEvent\n mouseleave: MapLibre.MapLayerMouseEvent\n sourceready: { map: MapLibre.Map, sourceId: string }\n}"
},
{
"name": "ScriptMapLibreGeolocateControlProps",
"kind": "interface",
"code": "interface ScriptMapLibreGeolocateControlProps {\n /** Position of the geolocate control. */\n position?: MapLibre.ControlPosition\n /** Options passed to `new maplibregl.GeolocateControl()`. */\n options?: MapLibre.GeolocateControlOptions\n}"
},
{
"name": "ScriptMapLibreGeolocateControlEvents",
"kind": "interface",
"code": "interface ScriptMapLibreGeolocateControlEvents {\n geolocate: MapLibre.GeolocateControlEventType['geolocate']\n error: MapLibre.GeolocateControlEventType['error']\n outofmaxbounds: MapLibre.GeolocateControlEventType['outofmaxbounds']\n trackuserlocationstart: MapLibre.GeolocateControlEventType['trackuserlocationstart']\n trackuserlocationend: MapLibre.GeolocateControlEventType['trackuserlocationend']\n userlocationfocus: MapLibre.GeolocateControlEventType['userlocationfocus']\n userlocationlostfocus: MapLibre.GeolocateControlEventType['userlocationlostfocus']\n unavailable: 'unsupported' | 'permission-denied'\n}"
},
{
"name": "ScriptMapLibreMapProps",
"kind": "interface",
Expand Down Expand Up @@ -898,6 +923,11 @@
"name": "ScriptMapLibrePopupSlots",
"kind": "interface",
"code": "interface ScriptMapLibrePopupSlots {\n default?: () => any\n}"
},
{
"name": "ScriptMapLibreScaleControlProps",
"kind": "interface",
"code": "interface ScriptMapLibreScaleControlProps {\n /** Position of the scale control. MapLibre places it bottom-left by default. */\n position?: MapLibre.ControlPosition\n /**\n * Options passed to `new maplibregl.ScaleControl()`.\n * `unit` also updates reactively through `setUnit()`.\n */\n options?: MapLibre.ScaleControlOptions\n}"
}
],
"matomo-analytics": [
Expand Down Expand Up @@ -4165,6 +4195,43 @@
"required": false
}
],
"ScriptMapLibreAttributionControlProps": [
{
"name": "position",
"type": "MapLibre.ControlPosition",
"required": false
},
{
"name": "options",
"type": "MapLibre.AttributionControlOptions",
"required": false,
"description": "Options passed to `new maplibregl.AttributionControl()`. Source attribution from the style and tiles always shows. `customAttribution` only adds text."
}
],
"ScriptMapLibreFullscreenControlProps": [
{
"name": "position",
"type": "MapLibre.ControlPosition",
"required": false
},
{
"name": "options",
"type": "MapLibre.FullscreenControlOptions",
"required": false
}
],
"ScriptMapLibreFullscreenControlEvents": [
{
"name": "fullscreenstart",
"type": "MapLibre.FullscreenControlEventType['fullscreenstart']",
"required": false
},
{
"name": "fullscreenend",
"type": "MapLibre.FullscreenControlEventType['fullscreenend']",
"required": false
}
],
"ScriptMapLibreGeoJsonProps": [
{
"name": "sourceId",
Expand Down Expand Up @@ -4240,6 +4307,62 @@
"description": "The source and layers exist on the map. Fires after the first add and after every re-add, such as after a style swap. A re-add clears feature state, so restore it here."
}
],
"ScriptMapLibreGeolocateControlProps": [
{
"name": "position",
"type": "MapLibre.ControlPosition",
"required": false
},
{
"name": "options",
"type": "MapLibre.GeolocateControlOptions",
"required": false
}
],
"ScriptMapLibreGeolocateControlEvents": [
{
"name": "geolocate",
"type": "MapLibre.GeolocateControlEventType['geolocate']",
"required": false
},
{
"name": "error",
"type": "MapLibre.GeolocateControlEventType['error']",
"required": false,
"description": "The Geolocation API returned an error. `code` 1 means the user denied permission. MapLibre then disables the button."
},
{
"name": "outofmaxbounds",
"type": "MapLibre.GeolocateControlEventType['outofmaxbounds']",
"required": false
},
{
"name": "trackuserlocationstart",
"type": "MapLibre.GeolocateControlEventType['trackuserlocationstart']",
"required": false
},
{
"name": "trackuserlocationend",
"type": "MapLibre.GeolocateControlEventType['trackuserlocationend']",
"required": false
},
{
"name": "userlocationfocus",
"type": "MapLibre.GeolocateControlEventType['userlocationfocus']",
"required": false
},
{
"name": "userlocationlostfocus",
"type": "MapLibre.GeolocateControlEventType['userlocationlostfocus']",
"required": false
},
{
"name": "unavailable",
"type": "'unsupported' | 'permission-denied'",
"required": false,
"description": "Geolocation cannot work in this browser. `permission-denied` means the user blocked it before the control loaded. MapLibre disables the button and fires no `error` event in both cases."
}
],
"ScriptMapLibreMapProps": [
{
"name": "trigger",
Expand Down Expand Up @@ -4537,6 +4660,19 @@
"required": false
}
],
"ScriptMapLibreScaleControlProps": [
{
"name": "position",
"type": "MapLibre.ControlPosition",
"required": false
},
{
"name": "options",
"type": "MapLibre.ScaleControlOptions",
"required": false,
"description": "Options passed to `new maplibregl.ScaleControl()`. `unit` also updates reactively through `setUnit()`."
}
],
"ScriptBlueskyEmbedProps": [
{
"name": "postUrl",
Expand Down
Loading
Loading