Composable Components 2
Miguel Camba
@miguelcamba
@cibernox
miguelcamba.com
Why?
- Wrappers around jQuery libraries
- They are not idiomatic to use
- Tricky to use with Ember Data colletions
- Nearly impossible to customize
They are monolithic blackboxes
L
M
A
O
arge
onolith with an
rmy of
ptions
(ノಥ益ಥ)ノ ┻━┻
We know better
Built with composition
{{power-select}}
{{basic-dropdown}}
{{ember-wormhole}}
{{power-select-multiple}}
Built for composition
You can't cover all use cases.
Face it.
But users can if you let them.
Demo
Why composition is so awesome?
- Stand on the shoulder of giants
- Compose focused components into complex ones
- Don't reinvent the wheel.
- Don't ship the same wheel twice
- More reliable results, faster than ever
{{power-select}}
{{basic-dropdown}}
{{ember-wormhole}}
{{power-select-multiple}}
{{power-select-sortable}}
{{ember-sortable}}
Composition 101
Use {{yield}} to expose yourself
<div class="basic-dropdown-trigger" onmousedown={{action "toggle"}}>
{{yield to="inverse"}}
</div>
{{#if opened}}
{{#ember-wormhole to=_wormholeDestination}}
<div class="ember-basic-dropdown-content">
{{yield (action "open") (action "close")}}
</div>
{{/ember-wormhole}}
{{/if}}
{{yield (action "open") (action "close")}}
Use {{yield}} to expose yourself
{{#basic-dropdown as |open close|}}
<button onclick={{close}}>Dismiss</button>
{{/basic-dropdown}}
Expose your public API only
<div class="basic-dropdown-trigger" onmousedown={{action "toggle"}}>
{{yield to="inverse"}}
</div>
{{#if opened}}
{{#ember-wormhole to=_wormholeDestination}}
<div class="ember-basic-dropdown-content">
{{yield (action "open") (action "close")}}
</div>
{{/ember-wormhole}}
{{/if}}
{{yield (hash open=(action "open") close=(action "close"))}}
Expose your public API only
{{#basic-dropdown as |dropdown|}}
<button onclick={{dropdown.close}}>Dismiss</button>
{{/basic-dropdown}}
Shape your public API as your component
<div class="basic-dropdown-trigger" onmousedown={{action "toggle"}}>
{{yield to="inverse"}}
</div>
{{#if opened}}
{{#ember-wormhole to=_wormholeDestination}}
<div class="ember-basic-dropdown-content">
{{yield (hash
opened=opened
actions=(hash
open=(action "open")
close=(action "close")
)
)}}
</div>
{{/ember-wormhole}}
{{/if}}
{{yield (hash
opened=opened
actions=(hash
open=(action "open")
close=(action "close")
)
)}}
Shape your public API as your component
{{#basic-dropdown as |dropdown|}}
<button onclick={{dropdown.actions.close}}>
Dismiss
</button>
{{/basic-dropdown}}
Compose APIs and expose it as one
{{#basic-dropdown as |dropdown|}}
{{#with (hash
isOpen=dropdown.isOpen
actions=(hash
open=(action dropdown.actions.open)
close=(action dropdown.actions.close)
select=(action "select" dropdown)
highlight=(action "highlight" dropdown)
search=(action "search" dropdown)
)) as |select|}}
<input type="text" oninput={{select.actions.search}}>
{{/with}}
{{#basic-dropdown as |dropdown|}}
{{#with (hash
isOpen=dropdown.isOpen
actions=(hash
open=(action dropdown.actions.open)
close=(action dropdown.actions.close)
select=(action "select" dropdown)
highlight=(action "highlight" dropdown)
search=(action "search" dropdown)
)) as |select|}}
<input type="text" oninput={{select.actions.search}}>
{{/with}}
Compose APIs and expose it as one
{{#power-select ... onchange=(action "foo") as |opt|}}
{{opt}}
{{/power-select}}
actions: {
foo(newValue, select, e) {
this.set('selected', newValue);
select.actions.close();
}
}
Compose for fun and profit
Thanks
Ember Power Select
By Miguel Camba
Ember Power Select
- 2,074