m2collective/filament-leaflet-map
Add interactive Leaflet maps to your Filament admin panels. This package provides map fields and location pickers for forms, letting users select coordinates, place markers, and work with geographic data directly inside Laravel applications.
composer require m2collective/filament-leaflet-map. Version 0.1.0 is the first tagged release, so pin the minor line ("m2collective/filament-leaflet-map": "0.1.*") until you've exercised it on a real form.src/ tree. Filament form components typically live under src/Forms/Components (or src/Fields), any published config under config/filament-leaflet-map.php, and asset registration in the service provider via FilamentAsset::register(). Confirm the exact component class and namespace there before wiring it into a form — at 0.1.0 the README may lag the code.PanelProvider: ->plugin(FilamentLeafletMapPlugin::make()). If it's a plain form field, no plugin registration is needed.php artisan filament:assets (Filament v3) or php artisan vendor:publish --tag=filament-leaflet-map-assets, depending on what the provider exposes.Basic field usage. Drop the component into a resource form and configure the viewport:
use M2Collective\FilamentLeafletMap\Forms\Components\LeafletMap; // verify namespace in src/
LeafletMap::make('location')
->label('Pick a location')
->center(lat: 51.505, lng: -0.09)
->zoom(12)
->required();
Storage patterns. Two viable shapes — pick one deliberately:
protected $casts = ['location' => 'array']; and let the field state be ['lat' => ..., 'lng' => ...]. Fastest to implement; hard to query spatially.latitude / longitude as decimal(10,7), mapped in and out of the widget with afterStateHydrated() and dehydrateStateUsing(). Use this whenever you need to sort, filter, or geo-index.Reusability. Wrap the configured field in a static factory (LocationMap::make()) or a small custom component so every form shares the same center, zoom, tile URL, and validation. Chained calls duplicated across a dozen resources is the most common drift point.
Reactivity. If the field supports live(), use ->live()->afterStateUpdated(fn ($state) => ...) to react to pin moves — reverse-geocoding into an address field, clearing a manually-entered suburb, or enabling a "confirm location" toggle.
Detail/view pages. If the package ships an infolist entry or Blade partial, reuse it on ViewRecord pages rather than hand-rolling map markup — you'll inherit the same tile and attribution config for free.
Testing. Drive the field through Livewire's fillForm([...]) / assertFormSet([...]) with a coordinate array. Never simulate map clicks in tests; the widget's client-side state isn't what your form validates.
0.1.0 ships no changelog beyond a compare link. Assume the public API can change between 0.1.x minors; pin and read the diff before bumping.$state on moveend/click — if it doesn't, the field is empty on save and it looks like a validation bug rather than a JS one.map.invalidateSize() after the container becomes visible, not a config change.[lat, lng]; GeoJSON and PostGIS speak lng, lat. Normalise at the storage boundary and never let raw widget state leak into a geo query.->afterStateUpdated(fn ($state) => dump($state)) to confirm what the server is receiving.How can I help you explore Laravel packages today?