ReadonlyidPane identifier. Becomes the desktop tab id (gl-rp-tab-<id>), the pane id
(gl-rp-pane-<id>) and the mobile sheet id — so it must be usable in a DOM id and in an
attribute selector.
Readonlylabeli18n key resolved at render time — never a literal, so the tab follows the language.
Optional ReadonlyiconSVG markup for the desktop tab, sanitised by the host before insertion.
⚠️ Optional, and it stays optional. The desktop strip went from vertical text to
icons because six spelled-out tabs overflowed the viewport; a pane registered by a
third party that predates that change has no icon to give, and must keep a readable
tab rather than a blank square. The host falls back to labelKey.
⚠️ The mobile sheet ignores it — it lists panes by name, where length costs nothing.
ReadonlyselectorCSS selector for the element the host adopts.
⚠️ The host MOVES this node rather than cloning it: one node, one set of listeners, and it is put back where it came from on close. A selector matching several elements takes the first.
Optional ReadonlyorderSort order among registered panes. Lower comes first.
OptionalonCalled by the host just before it adopts the element, every time the pane is shown.
🛑 This is how a pane gets BUILT ON DEMAND, and without it the registry is close to useless: an owner that constructs its panel on first use — the normal case, since building DOM nobody has asked for is waste — has no way of learning that its tab was clicked. Measured in the browser before this existed: the tab was there, it activated, and it showed an empty pane, because the only thing that ever built the panel was the plugin's own toolbar action.
⚠️ Must be idempotent: it fires on every open, not only the first.
A panel surface some module owns, offered to whichever host is live.