The Frippery panel favorites extensionsorta does half of this — it doesn’t suppress the box highlight, but it does add extra hover-highlighting to the elements inside it. (My mouse was over the speaker icon, in this screenshot:)
The individual icons are implemented as St.Button()s with both an St.Label() and an St.Icon() set, not St.Bin()s, but they’re all inside an St.BoxLayout() as you specified.
The extension code is downloadable from the link above, or by installing from e.g.o and looking in $HOME/.local/share/gnome-shell/extensions/Panel_Favorites@rmy.pobox.com/.
But basically, it looks like this is the meat of it:
class PanelLauncher {
constructor(app) {
this.actor = new St.Button({ style_class: 'panel-button',
reactive: true });
let gicon = app.app_info.get_icon();
let icon = new St.Icon({ gicon: gicon,
style_class: 'panel-launcher-icon'});
this.actor.set_child(icon);
this.label = new St.Label({ style_class: 'panel-launcher-label'});
this.label.set_text(text);
Main.layoutManager.addChrome(this.label);
this.label.hide();
this.actor.label_actor = this.label;
this.actor.connect('notify::hover',
this._onHoverChanged.bind(this));
this.actor.opacity = 207;
}
_onHoverChanged(actor) {
actor.opacity = actor.hover ? 255 : 207;
}
The styling on the label also seems to be involved in showing the hover effect:
Oh, hang on — whoops. Re-reading the code, I think the St.Label() is actually the tooltip for each icon. So it’s totally unrelated to the hover highlighting.