bh 6.9.2 → 6.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a00566adde28789768cc5886928cea8beda894754e6e69a02f92b9d2f1b04eda
4
- data.tar.gz: e145e5153def494578b3ece720f11cb3e1ce89a772b09507b75b3dc9d79772af
3
+ metadata.gz: 1698ddd9bc4657e18402fafa6a96ade1e5cebc16e81bb38f3dcdef8bbbf268f8
4
+ data.tar.gz: 27ae0e2709e2c8218489233b5501d3098cdfa8dcda5e60ac770aeb2354ba8bab
5
5
  SHA512:
6
- metadata.gz: eb9e51b70d0c16d6a51337ebe4f73333aee4d5ebda852308438718e7059ea3d4818d2510f7741d09f261ee708d44eb71ba9c8ed0f43fa65d461305507334b5c2
7
- data.tar.gz: 1d816cbefc43df66146259442266a68c21706479c98936163ddb51034d0f60ecca24f1b294619f013f8f397ae0fdd6ed6ffdde0d51f8ba711ad0f755c0d9572b
6
+ metadata.gz: c0cac35a163c597c2f14e84f79e6cefe1b0eb6ad2e08deba97162a1d0dad7dd3fc0d0a58a72180028d51f42a8e7c607d912cb0df8482c7fa1ed2805fe82f3585
7
+ data.tar.gz: 200643a93cea4bbfc54ca78679362042e5565525667573478624af65aaf68935565fb774981c947ed4ea1c1745e996ac1154c69bb9f5e845065c4ccb26e137e2
data/CHANGELOG.md CHANGED
@@ -8,6 +8,24 @@ For more information about changelogs, check
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## 6.10.1 - 2026-09-26
12
+
13
+ * [FIX] A tooltip closes when its icon, or the button or link holding it, is clicked
14
+
15
+ A click that takes the icon away — the sidebar's moon and sun swap places — left the tooltip
16
+ open with nothing under the pointer to close it, and Popper put it in the page's corner,
17
+ where a hidden element is. It is closed in the capture phase, before the click's own action
18
+ changes the page.
19
+
20
+ ## 6.10.0 - 2026-09-26
21
+
22
+ * [FEATURE] A pin or an area on a map leads where its row does
23
+
24
+ The map controller takes a point as `[lat, lng, href, title]` and a place as
25
+ `[id, href, title]`. A pin with an `href` is clickable, shows its `title` on hover, and a
26
+ click follows it through Turbo; an area filled on a boundary layer is followed the same
27
+ way. A bare `[lat, lng]` or a bare place ID still draws a pin that leads nowhere.
28
+
11
29
  ## 6.9.2 - 2026-09-20
12
30
 
13
31
  * [FIX] A small select's combobox is small too
@@ -6,6 +6,11 @@ import { load } from './map/loader.js'
6
6
  // none, a pin at the place; a row keeping coordinates is a pin there and then, with
7
7
  // nothing to look up. The key and the map are the host's, read from its credentials; the
8
8
  // rows are the page's, and the map is fitted round whatever it drew.
9
+ //
10
+ // A row may carry where it leads and what it is called: a point as `[lat, lng, href, title]`,
11
+ // a place as `[id, href, title]`, where a bare place ID or a bare `[lat, lng]` leads nowhere.
12
+ // A pin or an area with somewhere to lead is clicked through to it, the way the row's own
13
+ // link in the table is.
9
14
  export default class extends Controller {
10
15
  static values = { key: String, id: String, boundary: String, places: Array, points: Array }
11
16
 
@@ -30,7 +35,8 @@ export default class extends Controller {
30
35
  async place(map, bounds) {
31
36
  if (this.placesValue.length === 0) return
32
37
  const { Place } = await google.maps.importLibrary('places')
33
- const places = this.placesValue.map(id => new Place({ id }))
38
+ const rows = this.placesValue.map(row => [].concat(row))
39
+ const places = rows.map(([id, href, title]) => ({ place: new Place({ id }), href, title }))
34
40
 
35
41
  if (this.hasBoundaryValue) return this.fill(map, bounds, places)
36
42
  return this.pin(map, bounds, places)
@@ -38,13 +44,19 @@ export default class extends Controller {
38
44
 
39
45
  // The layer styles every boundary Google knows at that level, and a function saying
40
46
  // which of them are ours is what fills them in. The bounds are the places' viewports.
47
+ // An area with somewhere to lead is followed there when clicked.
41
48
  async fill(map, bounds, places) {
42
- const ours = new Set(this.placesValue)
43
- map.getFeatureLayer(this.boundaryValue).style = ({ feature }) => {
44
- if (ours.has(feature.placeId)) return FILLED
49
+ const hrefs = new Map(places.map(({ place, href }) => [place.id, href]))
50
+ const layer = map.getFeatureLayer(this.boundaryValue)
51
+ layer.style = ({ feature }) => {
52
+ if (hrefs.has(feature.placeId)) return FILLED
45
53
  }
54
+ layer.addListener('click', ({ features }) => {
55
+ const href = features.map(feature => hrefs.get(feature.placeId)).find(Boolean)
56
+ if (href) visit(href)
57
+ })
46
58
 
47
- await Promise.all(places.map(place =>
59
+ await Promise.all(places.map(({ place }) =>
48
60
  fetched(place, 'viewport').then(() => { if (place.viewport) bounds.union(place.viewport) })
49
61
  ))
50
62
  }
@@ -52,8 +64,8 @@ export default class extends Controller {
52
64
  async pin(map, bounds, places) {
53
65
  const drop = await this.dropper(map, bounds)
54
66
 
55
- await Promise.all(places.map(place =>
56
- fetched(place, 'location').then(() => { if (place.location) drop(place.location) })
67
+ await Promise.all(places.map(({ place, href, title }) =>
68
+ fetched(place, 'location').then(() => { if (place.location) drop(place.location, href, title) })
57
69
  ))
58
70
  }
59
71
 
@@ -62,20 +74,29 @@ export default class extends Controller {
62
74
  if (this.pointsValue.length === 0) return
63
75
  const drop = await this.dropper(map, bounds)
64
76
 
65
- for (const [lat, lng] of this.pointsValue) drop({ lat, lng })
77
+ for (const [lat, lng, href, title] of this.pointsValue) drop({ lat, lng }, href, title)
66
78
  }
67
79
 
68
- // One marker at a position, and the bounds widened to hold it.
80
+ // One marker at a position, and the bounds widened to hold it. A marker with somewhere to
81
+ // lead is clickable, names what it leads to on hover, and is followed there when clicked.
69
82
  async dropper(map, bounds) {
70
83
  const { AdvancedMarkerElement } = await google.maps.importLibrary('marker')
71
84
 
72
- return (position) => {
73
- new AdvancedMarkerElement({ map, position })
85
+ return (position, href, title) => {
86
+ const marker = new AdvancedMarkerElement({ map, position, title, gmpClickable: Boolean(href) })
87
+ if (href) marker.addEventListener('gmp-click', () => visit(href))
74
88
  bounds.extend(position)
75
89
  }
76
90
  }
77
91
  }
78
92
 
93
+ // Through Turbo where the page has it, so the table's frame and scroll behave as a click on
94
+ // the row's own link would; a plain navigation otherwise.
95
+ function visit(href) {
96
+ if (window.Turbo) window.Turbo.visit(href)
97
+ else window.location.assign(href)
98
+ }
99
+
79
100
  // A place that cannot be fetched — an ID Google no longer knows — is left off the map
80
101
  // rather than taking the rest of the page's rows with it.
81
102
  function fetched(place, field) {
@@ -10,14 +10,24 @@ import { Tooltip } from 'bootstrap'
10
10
  // is also what shows a tooltip, and a word popping up over a tap reads as a hitch.
11
11
  // Asked two ways, since an iPhone answered the first with a tooltip all the same: a
12
12
  // screen that cannot hover, or a pointer too coarse to rest on one word of a row.
13
+ //
14
+ // Closed by a click on the icon or on whatever holds it, a button or a link: what a click
15
+ // does may take the icon away — the sidebar's moon and sun swap places, a sorted heading
16
+ // is drawn again — and a tooltip whose icon is gone from under the pointer sees no mouse
17
+ // leave, stays open, and is put by Popper wherever a hidden element is: the page's corner.
18
+ // In the capture phase, so it closes before the click's own action changes the page.
13
19
  export default class extends Controller {
14
20
  connect() {
15
21
  if (matchMedia('(hover: none), (pointer: coarse)').matches) return
16
22
 
17
23
  this.tooltip = Tooltip.getOrCreateInstance(this.element)
24
+ this.holder = this.element.closest('button, a') || this.element
25
+ this.close = () => this.tooltip.hide()
26
+ this.holder.addEventListener('click', this.close, true)
18
27
  }
19
28
 
20
29
  disconnect() {
30
+ this.holder?.removeEventListener('click', this.close, true)
21
31
  this.tooltip?.dispose()
22
32
  }
23
33
  }
data/lib/bh/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Bh
2
2
  # Version of the gem, read by the gemspec and by hosts checking compatibility.
3
- VERSION = '6.9.2'
3
+ VERSION = '6.10.1'
4
4
  end