Skip to content

Instantly share code, notes, and snippets.

@sjohnr
Forked from AStoker/app.html
Last active June 8, 2017 03:16
Show Gist options
  • Save sjohnr/9dad4ff50433db57344b92b16c174e4b to your computer and use it in GitHub Desktop.
Save sjohnr/9dad4ff50433db57344b92b16c174e4b to your computer and use it in GitHub Desktop.
Select Material
<template>
<require from="./ux-select"></require>
<div style="margin: 20px 0;">
<ux-select options.bind="['Option 1', 'Option 2', '', 'Option 3']" value="Option 2"></ux-select>
</div>
<div style="margin: 20px 0;">
<ux-select options.bind="['Some other option', 'A second option', 'A third option', 'A really long fourth option that is wider than the known universe']"></ux-select>
</div>
<div style="margin: 20px 0;">
<ux-select options.bind="['CA', 'NE', 'WY']"></ux-select>
</div>
<div style="margin: 20px 0;">
<ux-select options.bind="['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']" value="February"></ux-select>
</div>
</template>
export class App {
}
<!doctype html>
<html>
<head>
<title>Aurelia</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:400,600,300,500,700,900,200|Source+Sans+Pro:400,300,600,700,900,200italic,300italic" rel="stylesheet" type="text/css" />-->
<!--<link href="http://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet" type="text/css" />-->
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Extended" rel="stylesheet" type="text/css" />
</head>
<body aurelia-app>
<h1>Loading...</h1>
<script src="https://jdanyow.github.io/rjs-bundle/node_modules/requirejs/require.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/config.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/bundles/aurelia.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/bundles/babel.js"></script>
<script>
require(['aurelia-bootstrapper']);
</script>
</body>
</html>
* {
font-family: 'Roboto', sans-serif;
font-size: 15px;
}
body {
padding: 16px;
}
select {
display: none;
}
input {
border: none;
height: 16px;
margin: 0;
}
button {
background: none;
padding: 4px 0 8px;
border: solid lightgrey;
border-width: 0 0 1px 0;
}
.material-icons-extended {
vertical-align: middle;
}
.select-dropdown {
display: inline-block;
position: absolute;
margin: 0 -16px;
}
.select-dropdown ul {
overflow-y: auto;
background: white;
}
.hidden {
/*display: none;*/
visibility: hidden;
}
ul {
/*margin: 0 16px;*/
margin: 0;
padding: 8px 0;
overflow-y: auto;
list-style: none;
border-radius: 3px;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.4);
}
li {
cursor: pointer;
margin: 0;
padding: 16px 3em 20px 16px;
line-height: 12px;
}
li:hover, .selected {
background-color: lightgrey;
}
li.sep {
cursor: inherit;
height: 1px;
margin: 0;
padding: 0;
background: lightgrey;
}
<template>
<require from="./ux-select.css"></require>
<div class="select">
<select id="${name}">
<option value="" show.bind="value">${placeholder}</option>
<option repeat.for="option of options" value="${option}" selected.bind="value !== '' && value === option">${option}</option>
</select>
<button ref="button" click.trigger="show()" mousedown.delegate="onMouseDown($event)">
<span class="label">${val}</span>
<span class="material-icons-extended">arrow_drop_down</span>
</button>
<div ref="dropdown" class="select-dropdown hidden">
<ul ref="list">
<li repeat.for="option of options" class="${option === '' ? 'sep' : ''} ${value !== '' && value === option ? 'selected' : ''}" mousedown.delegate="onSelect(option)">${option}</li>
</ul>
</div>
</div>
</template>
import {bindable, bindingMode} from 'aurelia-framework';
const GUTTER_OFFSET = 8;
const BASE_OFFSET = 15;
const OPTION_HEIGHT = 48;
function $promise(ms) {
return new Promise(x => setTimeout(x, ms));
}
export class UxSelect {
@bindable name;
@bindable options;
@bindable({ defaultBindingMode: bindingMode.twoWay }) value = '';
@bindable placeholder = 'Please select a value';
created() {
document.documentElement.addEventListener('mousedown', event => this.onMouseDown(event));
}
get val() {
return this.value ? this.value : this.placeholder;
}
onSelect(option) {
this.value = option;
}
show() {
let documentHeight = document.documentElement.clientHeight;
let maxHeight = documentHeight - GUTTER_OFFSET * 4;
let optionsHeight = this.dropdown.clientHeight;
let offset = BASE_OFFSET;
let index = this.options.indexOf(this.value);
if (index > 0) {
offset += OPTION_HEIGHT * index;
}
let x = this.button.offsetLeft;
let y = this.button.offsetTop - offset;
if (documentHeight < y + optionsHeight + GUTTER_OFFSET * 2) {
y = documentHeight - GUTTER_OFFSET - optionsHeight;
}
// double-check y-coord is off-screen and reset
if (y < 0) {
y = GUTTER_OFFSET;
}
this.dropdown.setAttribute('style', `left: ${x}px; top: ${y}px;`);
this.list.setAttribute('style', `max-height: ${maxHeight}px;`);
this.dropdown.classList.remove('hidden');
}
onMouseDown(e) {
this.dropdown.classList.add('hidden');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment