@aiaiai-pt/design-system 0.31.0 → 0.31.1

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.
@@ -15,7 +15,7 @@
15
15
  <script>
16
16
  import { fromLonLat } from 'ol/proj.js';
17
17
  import { boundingExtent } from 'ol/extent.js';
18
- import { createTileLayer, createMapStyles, createOverlayLayers, watchTheme, renderMapError } from './map-utils.js';
18
+ import { createTileLayer, createMapStyles, createOverlayLayers, clusterTooltipLabel, watchTheme, renderMapError } from './map-utils.js';
19
19
 
20
20
  let {
21
21
  /** @type {{ id: string, lon: number, lat: number, label?: string, [key: string]: any }[]} */
@@ -286,21 +286,21 @@
286
286
  return;
287
287
  }
288
288
 
289
- const clustered = feature.get('features');
290
289
  if (container) container.style.cursor = 'pointer';
291
290
 
292
- if (clustered?.length === 1) {
293
- const data = clustered[0].get('markerData');
294
- if (data?.label) {
295
- tooltipEl.textContent = data.label;
296
- tooltipEl.style.display = 'block';
297
- tooltipOverlay.setPosition(feature.getGeometry()?.getCoordinates());
298
- }
299
- } else {
300
- tooltipEl.textContent = `${clustered?.length ?? 0} items`;
301
- tooltipEl.style.display = 'block';
302
- tooltipOverlay.setPosition(feature.getGeometry()?.getCoordinates());
291
+ const label = clusterTooltipLabel(feature);
292
+ if (label == null) {
293
+ tooltipEl.style.display = 'none';
294
+ return;
303
295
  }
296
+ tooltipEl.textContent = label;
297
+ tooltipEl.style.display = 'block';
298
+ // Cluster features carry a Point geometry; raw overlay (file/WFS)
299
+ // features can be polygons/lines, so anchor those at the pointer.
300
+ const coords = feature.get('features') === undefined
301
+ ? evt.coordinate
302
+ : feature.getGeometry()?.getCoordinates();
303
+ tooltipOverlay.setPosition(coords);
304
304
  });
305
305
 
306
306
  // `popup` opens the anchored ficha-resumo overlay; otherwise `onclick`
@@ -374,7 +374,8 @@ export function getHeatmapGradient(el) {
374
374
  */
375
375
  export function geoStylerToFlat(style) {
376
376
  if (!style || typeof style !== "object") return {};
377
- if (!Array.isArray(style.rules)) return /** @type {OverlayLayerStyle} */ (style);
377
+ if (!Array.isArray(style.rules))
378
+ return /** @type {OverlayLayerStyle} */ (style);
378
379
  const sym = style.rules?.[0]?.symbolizers?.[0];
379
380
  if (!sym || typeof sym !== "object") return {};
380
381
  /** @type {OverlayLayerStyle} */
@@ -389,8 +390,10 @@ export function geoStylerToFlat(style) {
389
390
  if (typeof sym.width === "number") flat.strokeWidth = sym.width;
390
391
  } else if (sym.kind === "Fill") {
391
392
  if (typeof sym.color === "string") flat.fillColor = sym.color;
392
- if (typeof sym.outlineColor === "string") flat.strokeColor = sym.outlineColor;
393
- if (typeof sym.outlineWidth === "number") flat.strokeWidth = sym.outlineWidth;
393
+ if (typeof sym.outlineColor === "string")
394
+ flat.strokeColor = sym.outlineColor;
395
+ if (typeof sym.outlineWidth === "number")
396
+ flat.strokeWidth = sym.outlineWidth;
394
397
  }
395
398
  return flat;
396
399
  }
@@ -449,7 +452,9 @@ export async function createOverlayLayers(defs, styles) {
449
452
  const point = new Style({
450
453
  image: new CircleStyle({
451
454
  radius: flat.pointRadius ?? 6,
452
- fill: new Fill({ color: flat.pointColor ?? flat.strokeColor ?? "#3366cc" }),
455
+ fill: new Fill({
456
+ color: flat.pointColor ?? flat.strokeColor ?? "#3366cc",
457
+ }),
453
458
  stroke,
454
459
  }),
455
460
  });
@@ -484,6 +489,39 @@ export async function createOverlayLayers(defs, styles) {
484
489
  });
485
490
  }
486
491
 
492
+ // ─── Hover tooltip label ─────────────────────────────────────────
493
+
494
+ /**
495
+ * Decide the hover-tooltip text for a feature under the pointer.
496
+ *
497
+ * Markers passed via the `markers` prop go through an OL Cluster source, so
498
+ * each rendered feature carries a `features` collection: one entry → that
499
+ * marker's label; many → "N items". Features served from an overlay `layers`
500
+ * def (a file/WFS source) are added to a plain VectorSource and have NO
501
+ * `features` collection (`undefined`) — for those, fall back to the feature's
502
+ * own descriptive props rather than rendering the misleading "0 items".
503
+ *
504
+ * @param {{ get: (key: string) => any }} feature — an OL Feature (or any
505
+ * object exposing `.get(key)`).
506
+ * @returns {string | null} the label to show, or null to hide the tooltip.
507
+ */
508
+ export function clusterTooltipLabel(feature) {
509
+ const clustered = feature.get("features");
510
+ if (clustered === undefined) {
511
+ const label =
512
+ feature.get("name") ??
513
+ feature.get("title") ??
514
+ feature.get("label") ??
515
+ feature.get("markerData")?.label;
516
+ return label != null && String(label) !== "" ? String(label) : null;
517
+ }
518
+ if (clustered.length === 1) {
519
+ const data = clustered[0].get("markerData");
520
+ return data?.label ?? null;
521
+ }
522
+ return `${clustered.length} items`;
523
+ }
524
+
487
525
  // ─── Boundary (#187 D-e prep) ────────────────────────────────────
488
526
 
489
527
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiaiai-pt/design-system",
3
- "version": "0.31.0",
3
+ "version": "0.31.1",
4
4
  "description": "Design system tokens and Svelte components for aiaiai products",
5
5
  "license": "MIT",
6
6
  "type": "module",