Popover experiments: PopoverButton and support for Maplibre

I have been learning to use the brand new Popover component (released in Vaadin 24.5) and finding best practices. Currently I have a composition called PopoverButton in Viritin 2.10.0 and initial support for Maplibre component.

Popoover is essentially an special version of Dialog, which can be visually bound to another UI component, typically to some toolbar Button or similar. I have had a need for such in the for couple of occasions so I’m really happy we now have an official solution. For really old Vaadin versions there was PopupButton with latest versions, I have simply made a compromise and used dialog in the center of the screen.

The Popover itself has been implemented as a versitile building block for various uses cases. I guess the most typical is probably still the PopupButton style composition, where a button hides some less often needed functions. Typically for example Grid’s have limited space for a action buttons, so less commonly utilized actions must be hidden somehow. Thus, I decided to create a ready made composition that uses suitable configuration and saves you a couple of lines of code. A usage example below:

        public class OtherActions extends PopoverButton {
            public OtherActions(Person person) {
                super(() -> new VVerticalLayout(
                        new ActionButton("Merge.."),
                        new ActionButton("Send email"),
                        new ActionButton("Call"),
                        new ActionButton("SMS")));
                // The popover can be preconfigured via getter, instance is then created already
                // but the actual content (commonly the heavy part) is still postponed to UI interraction
                // If you want to avoid creation of the popover instance beforehand, do these in click listener instead
                getPopover().setWidth("30vw");
                getPopover().setHeight("45vh"); // optimally Popover would have implicit max height
            }

(ActionButton’s in the snippet are regular Vaadin buttons.)

The default “content” for the PopoverButton is VaadinIcon.ELLIPSIS_V, which is fine for my in many case, but can of course be configured. The API is also built in a way that guides you away from a trap with the built-it Popover API: pre-creating a lot of UI components in advance, that most often are not even needed. With e.g. with Grid’s or big listings could consume a ton of memory and CPU. The PopoverButton only instantiates the Button itself by default, and the content is generated one the user decides to open the Popover.

In addition to the PopoverButton, I created a similar “lazy loading API” for VPopover extention. The pattern can be used with core Popover as well, but requires some quirks to get all the bits in right.

Place any component on top of a map widget

In Maplibre (JS slippy map widget) lingo, popover is “popup”. In the Maplibre Vaadin add-on there has been a support for popup’s, but the implementation has been a bit handycapped, only supporting HTML content.

There is yet now release, in the snapshot verison you can use use the setPopover(Supplier popovercontentGenerator) method instead of withPopop(String html) if you want more complex content tied to your Markers.

In the implementation I used API (setFor(String)) I found via IDE as I don’t really have the actual element reference to markers generated by Maplibre on the Flow side. It seems to be a bit bit more “manual” then the default API, but magically (and to my slight surprise), once I got it showing up properly, the content follows to Marker smoothly if one pans the map :sunglasses: This opens a lot of new UI patterns for my GIS solutions.

I’m currently trying to seek for a solution how to tie to other “map components” than Markers. But for them I’d need to be able to tie the opening position under the cursor somehow (e.g. a polygon might be only half visible → can’t really tie to a component). If anybody has an idea how the accomplish this, I’d be happy to hear from you!

3 Likes