A solid, fully customizable, reactive dropdowns package for Meteor.
Install lookback:dropdowns
from Atmosphere:
meteor add lookback:dropdowns
{{ ! In a template }}
{{#dropdownTrigger name="uniqueName" }}
<button>Trigger</button>
{{/dropdownTrigger}}
{{#dropdown name="uniqueName"}}
<p>Hello world!</p>
{{/dropdown}}
A dropdown consist of a trigger and the actual dropdown content. They are wrapped in Meteor template helpers, in order to create contained components. The templates are:
dropdownTrigger
dropdown
Meteor's template helpers can take a bunch of arguments for customization, but the only required one for the dropdowns to work is the name
argument, which takes a string which should be unique in order to identify the dropdown.
Simply use the templates dropdownTrigger
and dropdown
in order to wrap the triggering element and the dropdown:
{{#dropdownTrigger name="dropdownTest" }}
<button>Trigger #1</button>
{{/dropdownTrigger}}
{{#dropdown name="dropdownTest"}}
<p>Hello world</p>
{{/dropdown}}
You can also use a separate template for the dropdown and dropdown trigger content:
{{ > dropdownTrigger name="testDropdown2" template="testDropdownTrigger" }}
{{ > dropdown name="testDropdown2" }}
<!-- Somewhere else .. -->
<template name="testDropdownTrigger">
<button>Trigger #2</button>
</template>
<template name="testDropdown2">
<p>External content, yo.</p>
</template>
Note that dropdownTrigger
needs the template name in the template
argument.
The dropdownTrigger
accepts these additional arguments:
hideOthers
- Defaults totrue
. Iffalse
, other visible dropdowns won't be hidden when a dropdown is toggled.
The dropdown
helper takes additional arguments for positioning and custom classes. The names are:
align
- Defaults tocenter
. Can also beleft
orright
.left
- Left offset in pixels. Defaults to0
.top
- Top offset in pixels. Defaults to0
.classes
- Additional class names for the dropdown. None as default.direction
- One ofn
,s
,e
orw
. Where to position the dropdown around the element. Defaults tos
.persistent
- Defaults tofalse
. Set totrue
if you want the dropdown not to hide when clicking outside it (ondocument
).
{{#dropdownTrigger name="testDropdown3"}}
<button>Custom dropdown</button>
{{/dropdownTrigger}}
{{#dropdown name="testDropdown3" align="right" top="20" left="10" direction="n" classes="custom-class another-one"}}
<p>Custom dropdown.</p>
{{/dropdown}}
The dropdownTrigger
template helper doesn't produce any extra HTML around your content. dropdown
on the other hand produces the following HTML:
{{#dropdownTrigger}}
<button>A trigger</button>
{{/dropdownTrigger}}
<!-- Produces: -->
<button class="dropdown__trigger">A trigger</button>
{{#dropdown name="testDropdown4" align="center" top="20" left="10" classes="custom-class"}}
<!-- Content [..] -->
{{/dropdown}}
<!-- Produces: -->
<div role="menu"
class="dropdown test-dropdown4 custom-class"
id="test-dropdown4"
style="position: absolute; left: XXpx; top: XXpx;"
data-dropdown-key="testDropdown4"
data-dropdown-align="center"
data-dropdown-left="10"
data-dropdown-top="20">
<div class="dropdown-arrow"></div>
<!-- Content [..] -->
</div>
As shown, name
, align
, left
and top
produces corresponding data-dropdown-
attributes in the markup, handy for custom CSS styling. The dropdown's name will be the id
attribute and applied as a class.
It is recommended to wrap both the trigger and dropdown markup in a container element with relative positioning.
Please note that the name
template argument will be present as id
and class
in snake-case form.
In order to detect active, opened dropdowns, the global dropdownIsActive
helper can be used:
{{#dropdownTrigger name="testDropdown5"}}
<button class="{{#if dropdownIsActive 'testDropdown5'}}dropdown--open{{/if}}">A trigger</button>
{{/dropdownTrigger}}
Both the dropdown and its trigger inherits the data context from its parent:
Template.testTemplate.helpers(
items: ['Foo', 'Bar', 'Baz']
)
<template name="testTemplate">
{{#dropdownTrigger name="testDropdown6"}}
<button>Dropdown with data</button>
{{/dropdownTrigger}}
{{#dropdown name="testDropdown6" classes="dropdown--menu" align="left"}}
<ul class="dropdown__menu">
{{#each items}}
<li role="menuItem"><a href="#">{{this}}</a></li>
{{/each}}
</ul>
{{/dropdown}}
</template>
One can build more complex components from this simple dropdown concept, such as filterables.
Dropdowns can be persistent too, which means they won't close when you click anywhere outside them. It's done setting persistent
to true
on a dropdown template:
{{#dropdownTrigger name="persistentDropdown"}}
<button>Persistent dropdown</button>
{{/dropdownTrigger}}
{{#dropdown name="persistentDropdown" persistent="true"}}
<p>
This one is persistent.
</p>
{{/dropdown}}
The dropdown uses the excellent Momentum package for creating natural animations when toggled. This is built on Meteor's UI hooks, since the dropdown content actually is removed from the DOM when hidden.
Two animations are included: spring
and appear
.
spring
is making the dropdown appear with a spring physics effect.appear
is simply showing and hiding the dropdown as-is.
You can change the default animation for all dropdowns by defining a new Momentum plugin and refer to it by its string name:
Dropdowns.animations.default = 'name-of-momentum-plugin';
You can also change animation per dropdown basis. Just specify the animation
attribute for the dropdown
helper.
<div class="test-area dropdown-container">
{{#dropdownTrigger name="appearAnimation"}}
<button>Non-standard animation</button>
{{/dropdownTrigger}}
{{#dropdown name="appearAnimation" animation="appear"}}
<p>Hey there.</p>
{{/dropdown}}
</div>
No CSS styling is provided with this dropdown package – it's up to you to style the dropdown according to your needs. For a complete styling example, check out the _dropdowns.scss
file in this repository.
This package exports a namespaced object: Dropdowns
. By the power of reactivity, all dropdowns are based on an underlying data structure which stores its (quite minimal) state. When that data changes, for instance if the position is changed over an API call, the UI will react. The Dropdowns
object has the following methods:
# This is the struct for a "dropdown" object, returned
# by Dropdowns.get('key')
{
name: 'key'
showing: false
align: 'center'
x: 0
y: 0
top: 10
left: 0
persistent: false
element: -> # jQuery reference to the dropdown component in the DOM.
}
# Manually create a dropdown with a name.
Dropdowns.create('name', opts = {top: 10, left: 0, align: 'center'})
# Get a the dropdown.
Dropdowns.get('name')
# Hide a dropdown.
Dropdowns.hide('name')
# Show a dropdown.
Dropdowns.show('name')
# Returns `true` if a dropdown is currently shown.
Dropdowns.isShown('name')
# Toggle a dropdown.
Dropdowns.toggle('name')
# Hide all dropdowns.
Dropdowns.hideAll()
# Destroy a dropdown.
Dropdowns.remove()
# Destroy all dropdowns.
Dropdowns.removeAll()
# Manually set a position of a dropdown. Both x and y are optional.
Dropdowns.setPosition('name', {x: Number, y: Number})
# Hide all dropdowns except for `name` (can also be an array of names).
Dropdowns.hideAllBut('name')
# Get names of all persistent dropdowns
Dropdowns.getPersistentKeys()
# Returns a dict of all dropdowns
Dropdowns.all()
# Position dropdown <name> around a DOM element <reference>
Dropdowns.positionDropdown('name', document.getElementById('reference'))
1.5.1
- Usekeyup
event for closing all dropdowns.1.5.0
- IntroducehideOthers
template option on a dropdown.1.4.2
- ExposeDropdowns.positionDropdown()
.1.4.1
- ExposeDropdowns.all()
.1.4.0
- Use
data-dropdown-key
attribute when positioning dropdowns, instead ofid
. - Expose dropdown name on the
name
property of a dropdown object. - Add
element()
function on dropdown objects returned fromDropdowns.get()
.element()
returns a jQuery reference to the DOM element for the dropdown.
- Use
1.3.0
- Add support for custom animations.1.2.1
- Addpersistent
option.1.2.0
- Add support for dropdown directions. Note that this release removes the default top offset (10px
).1.0.0
- Stable release.0.4.1
- Fix: The properties
x, y, top, left
are now flattened (before, they were in propertiesposition
andoffset
respectively). - Fix: Said properties are converted to
Numbers
when creating aDropdown
.
- Fix: The properties
0.4.0
Rewrite logic to be based on data reactivity instead of DOM state.- New: New API methods on the
Dropdowns
global. - New: New template helper for the dropdown trigger (
dropdownTrigger
).
- New: New API methods on the
0.3.3
Fix: Issue where a descendant element of a trigger would cause dropdown to hide.0.3.2
New: Add.dropdown__arrow
div to template.0.3.1
Fix: Support snake-case for classes and ids in dropdown template.0.3.0
Move foundational dropdown wrapper markup into the template.0.2.0
New: Support for horizontal positioning.0.1.0
Initial commit.
This package's API interface (methods on the Dropdown
object) is unit tested. Those tests reside in /tests
.
npm test
Contributions are welcome. Please open issues and/or file Pull Requests.
Made by Lookback.