mozilla/addon-sdk — pull request #1398 by ZER0 (2014-02-10 21:25:18+00:00)
Title: Bug 907450 - Anchored Panels

Depends by [pull 1376](https://github.com/mozilla/addon-sdk/pull/1376).

This patch allows SDK objects like `ActionButton`, `ToggleButton` and `Widget`, to be specified as Panel's `position` value.
Therefore with a code like that is possible have a `ToggleButton` turned in a "panel button":
```js
const { ToggleButton } = require('sdk/ui');
const { Panel } = require('sdk/panel');

let button = ToggleButton({
icon: './addon.png',
label: 'my button',
id: 'mybutton',
onChange: ({checked}) => checked && panel.show({position: button})
});

let panel = Panel({
contentURL: data.url('panel.html'),
onHide: window => button.state(window, {checked: false})
});
```
So developers can start to migrate from deprecated Widgets to new UI components.

They could easily create their own `PanelButton` as follows:

```js
const { ToggleButton } = require('sdk/ui');
const { Panel } = require('sdk/panel');

const { Class } = require('sdk/core/heritage');
const { data } = require('sdk/self');

const panels = new Map();

const PanelButton = Class({
extends: ToggleButton,
setup: function setup(options) {
ToggleButton.prototype.setup.call(this, options);

let panel = Panel({
contentURL: data.url(options.url),
onHide: window => this.state(window, {checked: false})
});

this.on('change', ({checked}) => checked && panel.show({position: this}));

panels.set(this, panel);
},

dispose: function dispose() {
ToggleButton.prototype.dispose.call(this);
panels.get(this).dispose();
panels.delete(this);
}
});

let button = PanelButton({
icon: './addon.png',
label: 'my button',
id: 'mybutton',
url: './foo.htm'
});
```

Ideally we'll provide in the close future a sugar syntax, probably not a class but a more generic function:
```js
const { ToggleButton, link } = require('sdk/ui');
const { Panel } = require('sdk/panel');

let button = ToggleButton({
icon: './addon.png',
label: 'my button',
id: 'mybutton'
});

let panel = Panel({
contentURL: data.url('panel.html')
});

// `link` takes UI components, "linking" them together.
// It could takes also `MenuItem`, `Sidebar`, `Toolbar`, etc.
link(button, panel);
```