@aiaiai-pt/design-system 0.26.0 → 0.28.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.
@@ -310,7 +310,14 @@
310
310
  if (!data) return;
311
311
  if (popup) {
312
312
  selected = data;
313
- if (coords) _popupOverlay?.setPosition(coords);
313
+ if (coords) {
314
+ _popupOverlay?.setPosition(coords);
315
+ // Fly TO the clicked marker: animate the view so the marker (and its
316
+ // anchored popup) is centred — a clear "the map moved to what I
317
+ // tapped" gesture, not a subtle edge-nudge. The small ficha-resumo
318
+ // card opens above the now-centred marker and stays in view.
319
+ map?.getView().animate({ center: coords, duration: 400 });
320
+ }
314
321
  } else {
315
322
  onclick?.(data);
316
323
  }
@@ -330,25 +337,31 @@
330
337
  (/** @type {any} */ (feature.getGeometry()))?.getCoordinates(),
331
338
  );
332
339
  } else if (clustered?.length > 1) {
333
- // A cluster of (near-)IDENTICAL coordinates can never split by
334
- // zooming (stacked reports at one point are common in civic
335
- // data) open the first item instead of zoom-looping forever.
340
+ // A cluster ALWAYS expands first zoom in toward it so the citizen
341
+ // picks an individual marker; only a SINGLE marker opens a popup.
342
+ // The lone exception is a genuinely STACKED pile (near-identical
343
+ // coords — stacked reports at one point are common in civic data)
344
+ // that can't split by zooming: once we're already at max zoom and
345
+ // it's still piled, fall back to opening the first item so it stays
346
+ // reachable instead of zoom-looping forever.
347
+ const view = map?.getView();
348
+ const currentZoom = view?.getZoom() ?? zoom;
349
+ const maxZoom = view?.getMaxZoom?.() ?? 19;
336
350
  const coords = clustered.map((f) => f.getGeometry()?.getCoordinates()).filter(Boolean);
337
351
  const lons = coords.map((c) => c[0]);
338
352
  const lats = coords.map((c) => c[1]);
339
353
  const spread = Math.max(...lons) - Math.min(...lons) + (Math.max(...lats) - Math.min(...lats));
340
- if (spread < 1) { // metres in web-mercator units — a stacked pile
354
+ const stacked = spread < 1; // metres in web-mercator units
355
+ if (stacked && currentZoom >= maxZoom - 0.5) {
341
356
  selectMarker(
342
357
  clustered[0].get('markerData'),
343
358
  (/** @type {any} */ (feature.getGeometry()))?.getCoordinates(),
344
359
  );
345
360
  return;
346
361
  }
347
- const view = map?.getView();
348
- const currentZoom = view?.getZoom() ?? zoom;
349
362
  view?.animate({
350
363
  center: feature.getGeometry()?.getCoordinates(),
351
- zoom: currentZoom + 2,
364
+ zoom: Math.min(currentZoom + 2, maxZoom),
352
365
  duration: 300,
353
366
  });
354
367
  }
@@ -139,6 +139,23 @@
139
139
 
140
140
  const boundaryRings = $derived(boundaryToRings(boundary));
141
141
 
142
+ // Recentre when `center` arrives or changes after mount. Consumers commonly
143
+ // resolve the centre asynchronously (after a boundary/config fetch), and the
144
+ // map-init effect reads `center` only PAST an `await`, so it is not tracked
145
+ // as a dependency there — without this the late centre is silently dropped
146
+ // and the map sits on its initial view (e.g. [0,0]). Skips once the user has
147
+ // placed a pin (`value`) so a late centre never yanks the map out from under
148
+ // a selection, and skips the [0,0] "unset" sentinel.
149
+ $effect(() => {
150
+ const c = center;
151
+ const map = _map;
152
+ if (!map || value) return;
153
+ if (!Array.isArray(c) || c.length !== 2) return;
154
+ if (c[0] === 0 && c[1] === 0) return;
155
+ const view = map.getView();
156
+ if (view) view.setCenter(fromLonLat(/** @type {[number, number]} */ (c)));
157
+ });
158
+
142
159
  /** @param {[number, number]} coords */
143
160
  function checkBoundary(coords) {
144
161
  if (!boundaryRings.length || !onoutofbounds) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiaiai-pt/design-system",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "Design system tokens and Svelte components for aiaiai products",
5
5
  "license": "MIT",
6
6
  "type": "module",