mirror of
https://github.com/home-assistant/frontend.git
synced 2026-09-28 16:04:00 +01:00
* Edit zones and locations on the map engine instead of leaflet-draw ha-locations-editor (zone config, the location selector, onboarding) used raw Leaflet layers and leaflet-draw, which pinned it to the Leaflet engine. Its interaction surface is three gestures - drag a marker, drag a zone center, drag a zone radius handle - so no editing library is needed. MapEngine gains an optional editing capability (draggable markers and an addEditableCircle primitive) plus panTo and containsLocation. Only the MapLibre engine implements editing: the circle geometry plus a draggable center marker and a draggable radius handle on the east edge, the radius derived from the great-circle distance between them, redrawn per frame while dragging. The handle has a touch-sized hit target and is a keyboard-operable slider with an accessible name. The Leaflet engine stays a viewing fallback: without WebGL2 an editor shows its locations as static markers and a notice that this browser cannot edit on the map. ha-map exposes editableLocations and fires editable-location-moved/resized/clicked and editing-available-changed. Locations are reconciled by id: position and radius changes move the existing handles, while a changed icon, name, color, or editability rebuilds the marker, so edits made in the form fields show up on the map on either engine. ha-locations-editor becomes a thin layer over that with its public contract unchanged, so its consumers need no changes; it reads localize from the internationalization context instead of taking hass. The zone panel no longer zooms the map when a selection comes from the map itself. Clicking or dragging a marker selects its list item, and mwc-list reports that programmatic selection with the same "property" request-selected event a click ends with. The two are told apart by timing: a selection from the map has already set the active entry when its event arrives, while a click's event arrives before the handler sets it. Skipping the programmatic event also keeps the item selected, which the shared request-selected helper would otherwise reset. The layers property and the engine selector are removed along with the leaflet-draw dependency and its patch: Leaflet is now purely the viewing fallback, selected by WebGL2 support alone. The Leaflet engine keeps a leafletMap field for the ha-map fit tests, which run on it in jsdom. * Keep the retained circle data current while resizing The engine keeps its source specifications to rebuild them after a style swap; the editable circle's redraw updates that copy along with the map. * Address code review on map editing Editable markers, the circle center on both engines, and the static fallback center activate on Enter and Space, as their button role promises. Locations without a name get a localized one, since onboarding and the location selector pass none. The resize handle's advertised maximum follows the radius instead of being exceeded by it, and the handle stays near the circle at high latitudes. Clicking the active zone row zoomed to it again upstream but was swallowed by the check that told a map-driven selection from a click; a one-shot flag on selections made in code replaces that inference. The engine rebuilds its sources from its own record on a style swap, so a radius changed while the style was unloaded is not lost. * Test the map editing path The MapLibre engine's editable circle against the fake map: dragging the center moves the circle and the handle and reports the drop, dragging the handle resizes and snaps it back, arrow keys resize in steps committed on release, the advertised maximum follows a larger radius, one update echoing pre-drag values is ignored, the center activates by click, Enter and Space but not after a drag, and removal clears markers, layers and listeners. ha-map's reconciliation of editable locations through a fake engine with editing support: circles and markers are drawn, moved in place, rebuilt when their appearance changes and removed when dropped, move, resize and activation events carry the location id, and an engine without editing support shows the locations statically. * Leave zone row selection to the user Clicking or dragging a zone on the map, and saving one in the dialog, selected its row in code. That selection fires the same request-selected event a click ends with, so the page had to tell the two apart, and the row could not be shown selected and stay clickable at the same time: the highlight never actually appeared. The list now only follows the user's own clicks, which removes that bookkeeping along with the zoom that a radius drag used to trigger. * Hand marker elements back clean, and record sources before the style loads MapLibre leaves its positioning class and transform on a marker element after removal. Hosts like ha-locations-editor cache their elements and hand them to whatever engine draws next: after a fatal WebGL failure that is the Leaflet fallback, which shows the locations statically. A removed element, and every element still on the map when the engine is destroyed, is reset so it arrives as a plain element. The editable circle's center gets the same treatment. Custom sources and layers are now recorded when added and only inserted into the map once the style has loaded. A circle moved while a swapped style was still loading therefore reaches the record, and a swap in that window carries it over; the deferred insert skips what the swap already placed. * Guard a keyboard resize against host updates like a drag Arrow-key resizing changed the radius without arming the pre-edit guard that pointer drags use, so a host re-render with the old radius while a key was held, or its echo right after the commit, snapped the circle back. A key resize now counts as a drag from the first key press until the commit. * Let the engine own the drag cursor, and tidy the fallback notice The move cursor came from stylesheets keyed on whether a location may be edited, so it showed on circles that cannot move and on the static Leaflet fallback. The MapLibre engine now sets it on the elements it actually made draggable and clears it when handing them back. The fallback notice said the browser cannot edit locations, while clicking the map to place one still works there; it now names what is missing, dragging markers and resizing zones. The editor's internationalization context is reactive, like its neighbours. * Show the fallback notice only when a location is editable The Leaflet fallback showed the notice for every editor, including ones whose locations are all read-only, where nothing is missing. * Drop the named icon's move cursor, and describe the fallback as a map state The Leaflet fallback draws named location icons statically, but the stylesheet still gave the ones marked editable a move cursor. The engine sets that cursor on the elements it actually drags, so the rule goes. The fallback notice blamed the browser, while MapLibre can also be unavailable after a failed start or a lost WebGL context; it now describes what the map offers. The resize handle's east point only guards the pole itself, so its distance agrees with distanceMeters wherever a zone can be. * Announce the fallback notice, and let test frames redraw The notice appears after the engine has been chosen, so helper text would not reach a screen reader; it is an alert now. The engine test's frame stub returned an id that landed in the engine's pending frame after the callback had cleared it, so every redraw after the first was skipped. * Show the fallback notice over the map, and keep handle clicks off the map The notice followed a map that fills the editor's fixed height, so it landed outside the box: clipped in onboarding, spilling into the form in the location selector. It now sits over the top of the map, clear of the zoom control. The resize handle was the one marker whose click reached MapLibre's map click, which a pin-on-click host takes as a request to move the location there; the handle stops it like the other markers do. * Share one circle geometry, and keep arrow keys on the handle Drawing, fitting, and handle placement each converted meters to degrees on their own, with different pole guards, so above 89.4 degrees the resize handle left the drawn circle. They now share one conversion that also agrees with distanceMeters; only the pole itself is guarded. Arrow keys on the resize handle also reached MapLibre's keyboard handler and panned the map while resizing; the handle keeps them. * Drop the zone page's active entry It only re-selected the row the user had just clicked, after the shared request-selected helper had reset it, which fired the selection event a second time and zoomed to the zone twice. The row highlight comes from the list itself and nothing else read the value, so the list no longer mirrors a selection at all. * Make marker activation opt-in, and relabel handles on language change Every editable marker was a focusable button whose activation fired an event, whether or not the host did anything with it: the zone page and the location selector do not. Activation is now opt-in per location; the onboarding search results opt in, and a marker that does not act on it is draggable without button semantics. The engine contract separates taking pointer input from being a keyboard-focusable button for that. Marker titles and handle labels are localized when drawn, so a language change, or localization arriving after the first draw, redraws them. * Own the accessibility attributes the engine sets, and use spherical circle geometry setMarkerAccessibility only filled in what was missing and nothing removed it, so a cached element rebuilt with a new title or a different role kept the old attributes. The helper now records what it set, replaces exactly that on a rebuild, and clears it when the element leaves the map, while a caller's own attributes stay untouched. The flat meters-to-degrees conversion broke down for large circles near the poles, wrapping longitude and producing latitudes beyond 90. Handle placement and the polygon now use the great-circle destination, and the fitted bounds a spherical box that spans all longitudes once the circle reaches a pole, so all three agree with distanceMeters everywhere.