feat(picker): WIP initial check in of picker component

This commit is contained in:
Brandy Carney
2017-10-13 16:40:28 -04:00
parent 20c0062be5
commit 7fc0310896
10 changed files with 1998 additions and 0 deletions

View File

@ -0,0 +1,73 @@
import { Component, Listen, Method } from '@stencil/core';
import { Picker, PickerEvent, PickerOptions } from '../../index';
@Component({
tag: 'ion-picker-controller'
})
export class PickerController {
private ids = 0;
private pickerResolves: {[pickerId: string]: Function} = {};
private pickers: Picker[] = [];
@Method()
create(opts?: PickerOptions): Promise<Picker> {
// create ionic's wrapping ion-picker component
const picker = document.createElement('ion-picker');
const id = this.ids++;
// give this picker a unique id
picker.id = `picker-${id}`;
picker.style.zIndex = (20000 + id).toString();
// convert the passed in picker options into props
// that get passed down into the new picker
Object.assign(picker, opts);
// append the picker element to the document body
const appRoot = document.querySelector('ion-app') || document.body;
appRoot.appendChild(picker as any);
// store the resolve function to be called later up when the picker loads
return new Promise<Picker>(resolve => {
this.pickerResolves[picker.id] = resolve;
});
}
@Listen('body:ionPickerDidLoad')
protected viewDidLoad(ev: PickerEvent) {
const picker = ev.detail.picker;
const pickerResolve = this.pickerResolves[picker.id];
if (pickerResolve) {
pickerResolve(picker);
delete this.pickerResolves[picker.id];
}
}
@Listen('body:ionPickerWillPresent')
protected willPresent(ev: PickerEvent) {
this.pickers.push(ev.detail.picker);
}
@Listen('body:ionPickerWillDismiss, body:ionPickerDidUnload')
protected willDismiss(ev: PickerEvent) {
const index = this.pickers.indexOf(ev.detail.picker);
if (index > -1) {
this.pickers.splice(index, 1);
}
}
@Listen('body:keyup.escape')
protected escapeKeyUp() {
const lastPicker = this.pickers[this.pickers.length - 1];
if (lastPicker) {
lastPicker.dismiss();
}
}
}

View File

@ -0,0 +1,26 @@
import { Animation } from '../../../index';
/**
* iOS Loading Enter Animation
*/
export default function iOSEnterAnimation(Animation: Animation, baseElm: HTMLElement): Animation {
const baseAnimation = new Animation();
const backdropAnimation = new Animation();
backdropAnimation.addElement(baseElm.querySelector('.picker-backdrop'));
const wrapperAnimation = new Animation();
wrapperAnimation.addElement(baseElm.querySelector('.picker-wrapper'));
backdropAnimation.fromTo('opacity', 0.01, 0.26);
wrapperAnimation.fromTo('translateY', '100%', '0%');
return baseAnimation
.addElement(baseElm)
.easing('ease-in-out')
.duration(200)
.add(backdropAnimation)
.add(wrapperAnimation);
}

View File

@ -0,0 +1,26 @@
import { Animation } from '../../../index';
/**
* iOS Loading Leave Animation
*/
export default function iOSLeaveAnimation(Animation: Animation, baseElm: HTMLElement): Animation {
const baseAnimation = new Animation();
const backdropAnimation = new Animation();
backdropAnimation.addElement(baseElm.querySelector('.picker-backdrop'));
const wrapperAnimation = new Animation();
wrapperAnimation.addElement(baseElm.querySelector('.picker-wrapper'));
backdropAnimation.fromTo('opacity', 0.26, 0.01);
wrapperAnimation.fromTo('translateY', '0%', '100%');
return baseAnimation
.addElement(baseElm)
.easing('ease-in-out')
.duration(200)
.add(backdropAnimation)
.add(wrapperAnimation);
}

View File

@ -0,0 +1,477 @@
import { Component, Element, Prop } from '@stencil/core';
import { PickerColumn } from '../../index';
@Component({
tag: 'ion-picker-column',
host: {
theme: 'picker-col'
}
})
export class PickerColumnCmp {
velocity: number;
optHeight: number;
@Element() el: HTMLElement;
@Prop() col: PickerColumn;
optClick(ev: Event, index: number) {
if (!this.velocity) {
ev.preventDefault();
ev.stopPropagation();
this.setSelected(index, 150);
}
}
setSelected(selectedIndex: number, duration: number) {
// if there is a selected index, then figure out it's y position
// if there isn't a selected index, then just use the top y position
let y = (selectedIndex > -1) ? ((selectedIndex * this.optHeight) * -1) : 0;
// this._plt.cancelRaf(this.rafId);
this.velocity = 0;
// so what y position we're at
this.update(y, duration, true, true);
}
update(y: number, duration: number, saveY: boolean, emitChange: boolean) {
// ensure we've got a good round number :)
y = Math.round(y);
// let i: number;
// let button: any;
// let opt: any;
// let optOffset: number;
// let visible: boolean;
// let translateX: number;
// let translateY: number;
// let translateZ: number;
// let rotateX: number;
// let transform: string;
// let selected: boolean;
const parent = this.el.querySelector('.picker-opts');
// const children = parent.children;
// const length = children.length;
// const selectedIndex = this.col.selectedIndex = Math.min(Math.max(Math.round(-y / this.optHeight), 0), length - 1);
// const durationStr = (duration === 0) ? null : duration + 'ms';
// const scaleStr = `scale(${this.scaleFactor})`;
// for (i = 0; i < length; i++) {
// button = children[i];
// opt = <any>this.col.options[i];
// optOffset = (i * this.optHeight) + y;
// visible = true;
// transform = '';
// if (this.rotateFactor !== 0) {
// rotateX = optOffset * this.rotateFactor;
// if (Math.abs(rotateX) > 90) {
// visible = false;
// } else {
// translateX = 0;
// translateY = 0;
// translateZ = 90;
// transform = `rotateX(${rotateX}deg) `;
// }
// } else {
// translateX = 0;
// translateZ = 0;
// translateY = optOffset;
// if (Math.abs(translateY) > 170) {
// visible = false;
// }
// }
// selected = selectedIndex === i;
// if (visible) {
// transform += `translate3d(0px,${translateY}px,${translateZ}px) `;
// if (this.scaleFactor !== 1 && !selected) {
// transform += scaleStr;
// }
// } else {
// transform = 'translate3d(-9999px,0px,0px)';
// }
// // Update transition duration
// if (duration !== opt._dur) {
// opt._dur = duration;
// button.style[this._plt.Css.transitionDuration] = durationStr;
// }
// // Update transform
// if (transform !== opt._trans) {
// opt._trans = transform;
// button.style[this._plt.Css.transform] = transform;
// }
// // Update selected item
// if (selected !== opt._selected) {
// opt._selected = selected;
// if (selected) {
// button.classList.add(PICKER_OPT_SELECTED);
// } else {
// button.classList.remove(PICKER_OPT_SELECTED);
// }
// }
// }
// this.col.prevSelected = selectedIndex;
// if (saveY) {
// this.y = y;
// }
// if (emitChange) {
// if (this.lastIndex === undefined) {
// // have not set a last index yet
// this.lastIndex = this.col.selectedIndex;
// } else if (this.lastIndex !== this.col.selectedIndex) {
// // new selected index has changed from the last index
// // update the lastIndex and emit that it has changed
// this.lastIndex = this.col.selectedIndex;
// var ionChange = this.ionChange;
// if (ionChange.observers.length > 0) {
// this._zone.run(ionChange.emit.bind(ionChange, this.col.options[this.col.selectedIndex]));
// }
// }
// }
}
render() {
console.log('picker column, render col', this.col);
let col = this.col;
const pickerPrefix: any[] = [];
if (col.prefix) {
pickerPrefix.push(
<div class="picker-prefix" style={{width: col.prefixWidth}}>
{col.prefix}
</div>
);
}
// if (this.content) {
// pickerPrefix.push(
// <div class='loading-content'>
// {this.content}
// </div>
// );
// }
return [
{ pickerPrefix },
<div class="picker-opts" style={{maxWidth: col.optionsWidth}}>
{col.options.map((o, index) =>
<button
class={{'picker-opt': true, 'picker-opt-disabled': o.disabled}}
disable-activated
onClick={() => this.optClick(event, index)}>
{o.text}
</button>
)}
</div>
];
}
}
// /**
// * @hidden
// */
// @Component({
// selector: '.picker-col',
// template:
// '<div *ngIf="col.prefix" class="picker-prefix" [style.width]="col.prefixWidth">{{col.prefix}}</div>' +
// '<div class="picker-opts" #colEle [style.max-width]="col.optionsWidth">' +
// '<button *ngFor="let o of col.options; let i=index"' +
// '[class.picker-opt-disabled]="o.disabled" ' +
// 'class="picker-opt" disable-activated (click)="optClick($event, i)">' +
// '{{o.text}}' +
// '</button>' +
// '</div>' +
// '<div *ngIf="col.suffix" class="picker-suffix" [style.width]="col.suffixWidth">{{col.suffix}}</div>',
// host: {
// '[style.max-width]': 'col.columnWidth',
// '[class.picker-opts-left]': 'col.align=="left"',
// '[class.picker-opts-right]': 'col.align=="right"',
// }
// })
// export class PickerColumnCmp {
// @ViewChild('colEle') colEle: ElementRef;
// @Input() col: PickerColumn;
// y: number = 0;
// colHeight: number;
// velocity: number;
// pos: number[] = [];
// startY: number = null;
// rafId: number;
// bounceFrom: number;
// minY: number;
// maxY: number;
// rotateFactor: number;
// scaleFactor: number;
// lastIndex: number;
// lastTempIndex: number;
// decelerateFunc: Function;
// debouncer: DomDebouncer;
// events: UIEventManager;
// @Output() ionChange: EventEmitter<any> = new EventEmitter();
// constructor(
// config: Config,
// private _plt: Platform,
// private elementRef: ElementRef,
// private _zone: NgZone,
// private _haptic: Haptic,
// plt: Platform,
// domCtrl: DomController,
// ) {
// this.events = new UIEventManager(plt);
// this.rotateFactor = config.getNumber('pickerRotateFactor', 0);
// this.scaleFactor = config.getNumber('pickerScaleFactor', 1);
// this.decelerateFunc = this.decelerate.bind(this);
// this.debouncer = domCtrl.debouncer();
// }
// ngAfterViewInit() {
// // get the scrollable element within the column
// let colEle: HTMLElement = this.colEle.nativeElement;
// this.colHeight = colEle.clientHeight;
// // get the height of one option
// this.optHeight = (colEle.firstElementChild ? colEle.firstElementChild.clientHeight : 0);
// // Listening for pointer events
// this.events.pointerEvents({
// element: this.elementRef.nativeElement,
// pointerDown: this.pointerStart.bind(this),
// pointerMove: this.pointerMove.bind(this),
// pointerUp: this.pointerEnd.bind(this),
// capture: true,
// zone: false
// });
// }
// ngOnDestroy() {
// this._plt.cancelRaf(this.rafId);
// this.events.destroy();
// }
// pointerStart(ev: UIEvent): boolean {
// console.debug('picker, pointerStart', ev.type, this.startY);
// this._haptic.gestureSelectionStart();
// // We have to prevent default in order to block scrolling under the picker
// // but we DO NOT have to stop propagation, since we still want
// // some "click" events to capture
// ev.preventDefault();
// // cancel any previous raf's that haven't fired yet
// this._plt.cancelRaf(this.rafId);
// // remember where the pointer started from`
// this.startY = pointerCoord(ev).y;
// // reset everything
// this.velocity = 0;
// this.pos.length = 0;
// this.pos.push(this.startY, Date.now());
// let options = this.col.options;
// let minY = (options.length - 1);
// let maxY = 0;
// for (var i = 0; i < options.length; i++) {
// if (!options[i].disabled) {
// minY = Math.min(minY, i);
// maxY = Math.max(maxY, i);
// }
// }
// this.minY = (minY * this.optHeight * -1);
// this.maxY = (maxY * this.optHeight * -1);
// return true;
// }
// pointerMove(ev: UIEvent) {
// ev.preventDefault();
// ev.stopPropagation();
// let currentY = pointerCoord(ev).y;
// this.pos.push(currentY, Date.now());
// this.debouncer.write(() => {
// if (this.startY === null) {
// return;
// }
// // update the scroll position relative to pointer start position
// let y = this.y + (currentY - this.startY);
// if (y > this.minY) {
// // scrolling up higher than scroll area
// y = Math.pow(y, 0.8);
// this.bounceFrom = y;
// } else if (y < this.maxY) {
// // scrolling down below scroll area
// y += Math.pow(this.maxY - y, 0.9);
// this.bounceFrom = y;
// } else {
// this.bounceFrom = 0;
// }
// this.update(y, 0, false, false);
// let currentIndex = Math.max(Math.abs(Math.round(y / this.optHeight)), 0);
// if (currentIndex !== this.lastTempIndex) {
// // Trigger a haptic event for physical feedback that the index has changed
// this._haptic.gestureSelectionChanged();
// this.lastTempIndex = currentIndex;
// }
// });
// }
// pointerEnd(ev: UIEvent) {
// ev.preventDefault();
// this.debouncer.cancel();
// if (this.startY === null) {
// return;
// }
// console.debug('picker, pointerEnd', ev.type);
// this.velocity = 0;
// if (this.bounceFrom > 0) {
// // bounce back up
// this.update(this.minY, 100, true, true);
// return;
// } else if (this.bounceFrom < 0) {
// // bounce back down
// this.update(this.maxY, 100, true, true);
// return;
// }
// let endY = pointerCoord(ev).y;
// this.pos.push(endY, Date.now());
// let endPos = (this.pos.length - 1);
// let startPos = endPos;
// let timeRange = (Date.now() - 100);
// // move pointer to position measured 100ms ago
// for (var i = endPos; i > 0 && this.pos[i] > timeRange; i -= 2) {
// startPos = i;
// }
// if (startPos !== endPos) {
// // compute relative movement between these two points
// var timeOffset = (this.pos[endPos] - this.pos[startPos]);
// var movedTop = (this.pos[startPos - 1] - this.pos[endPos - 1]);
// // based on XXms compute the movement to apply for each render step
// var velocity = ((movedTop / timeOffset) * FRAME_MS);
// this.velocity = clamp(-MAX_PICKER_SPEED, velocity, MAX_PICKER_SPEED);
// }
// if (Math.abs(endY - this.startY) > 3) {
// var y = this.y + (endY - this.startY);
// this.update(y, 0, true, true);
// }
// this.startY = null;
// this.decelerate();
// }
// decelerate() {
// let y = 0;
// if (isNaN(this.y) || !this.optHeight) {
// // fallback in case numbers get outta wack
// this.update(y, 0, true, true);
// this._haptic.gestureSelectionEnd();
// } else if (Math.abs(this.velocity) > 0) {
// // still decelerating
// this.velocity *= DECELERATION_FRICTION;
// // do not let it go slower than a velocity of 1
// this.velocity = (this.velocity > 0)
// ? Math.max(this.velocity, 1)
// : Math.min(this.velocity, -1);
// y = Math.round(this.y - this.velocity);
// if (y > this.minY) {
// // whoops, it's trying to scroll up farther than the options we have!
// y = this.minY;
// this.velocity = 0;
// } else if (y < this.maxY) {
// // gahh, it's trying to scroll down farther than we can!
// y = this.maxY;
// this.velocity = 0;
// }
// var notLockedIn = (y % this.optHeight !== 0 || Math.abs(this.velocity) > 1);
// this.update(y, 0, true, !notLockedIn);
// if (notLockedIn) {
// // isn't locked in yet, keep decelerating until it is
// this.rafId = this._plt.raf(this.decelerateFunc);
// }
// } else if (this.y % this.optHeight !== 0) {
// // needs to still get locked into a position so options line up
// var currentPos = Math.abs(this.y % this.optHeight);
// // create a velocity in the direction it needs to scroll
// this.velocity = (currentPos > (this.optHeight / 2) ? 1 : -1);
// this._haptic.gestureSelectionEnd();
// this.decelerate();
// }
// let currentIndex = Math.max(Math.abs(Math.round(y / this.optHeight)), 0);
// if (currentIndex !== this.lastTempIndex) {
// // Trigger a haptic event for physical feedback that the index has changed
// this._haptic.gestureSelectionChanged();
// }
// this.lastTempIndex = currentIndex;
// }
// refresh() {
// let min = this.col.options.length - 1;
// let max = 0;
// const options = this.col.options;
// for (var i = 0; i < options.length; i++) {
// if (!options[i].disabled) {
// min = Math.min(min, i);
// max = Math.max(max, i);
// }
// }
// const selectedIndex = clamp(min, this.col.selectedIndex, max);
// if (this.col.prevSelected !== selectedIndex) {
// var y = (selectedIndex * this.optHeight) * -1;
// this._plt.cancelRaf(this.rafId);
// this.velocity = 0;
// this.update(y, 150, true, false);
// }
// }
// }

View File

@ -0,0 +1,219 @@
@import "../../themes/ionic.globals.ios";
@import "./picker";
// iOS Picker
// --------------------------------------------------
/// @prop - Height of the picker wrapper
$picker-ios-height: 260px !default;
/// @prop - Border color of the picker wrapper
$picker-ios-border-color: $list-ios-border-color !default;
/// @prop - Background of the picker wrapper
$picker-ios-background-color: $list-ios-background-color !default;
/// @prop - Height of the picker toolbar
$picker-ios-toolbar-height: 44px !default;
/// @prop - Background color of the picker toolbar
$picker-ios-toolbar-background-color: $picker-ios-background-color !default;
/// @prop - Height of the picker button
$picker-ios-button-height: $picker-ios-toolbar-height !default;
/// @prop - Text color of the picker button
$picker-ios-button-text-color: color($colors-ios, primary) !default;
/// @prop - Background of the picker button
$picker-ios-button-background-color: transparent !default;
/// @prop - Font size of the picker button
$picker-ios-button-font-size: 1.6rem !default;
/// @prop - Padding top of the picker button
$picker-ios-button-padding-top: 0 !default;
/// @prop - Padding end of the picker button
$picker-ios-button-padding-end: 1em !default;
/// @prop - Padding bottom of the picker button
$picker-ios-button-padding-bottom: $picker-ios-button-padding-top !default;
/// @prop - Padding start of the picker button
$picker-ios-button-padding-start: $picker-ios-button-padding-end !default;
/// @prop - Font weight of the strong picker button
$picker-ios-button-strong-font-weight: 600 !default;
/// @prop - Padding top of the picker column
$picker-ios-column-padding-top: 0 !default;
/// @prop - Padding end of the picker column
$picker-ios-column-padding-end: 4px !default;
/// @prop - Padding bottom of the picker column
$picker-ios-column-padding-bottom: $picker-ios-column-padding-top !default;
/// @prop - Padding start of the picker column
$picker-ios-column-padding-start: $picker-ios-column-padding-end !default;
/// @prop - Perspective of the picker column
$picker-ios-column-perspective: 1000px !default;
/// @prop - Padding top of the picker option
$picker-ios-option-padding-top: 0 !default;
/// @prop - Padding end of the picker option
$picker-ios-option-padding-end: $picker-ios-option-padding-top !default;
/// @prop - Padding bottom of the picker option
$picker-ios-option-padding-bottom: $picker-ios-option-padding-top !default;
/// @prop - Padding start of the picker option
$picker-ios-option-padding-start: $picker-ios-option-padding-end !default;
/// @prop - Text color of the picker option
$picker-ios-option-text-color: $list-ios-text-color !default;
/// @prop - Font size of the picker option
$picker-ios-option-font-size: 20px !default;
/// @prop - Height of the picker option
$picker-ios-option-height: 42px !default;
/// @prop - Offset y of the picker option
$picker-ios-option-offset-y: (($picker-ios-height - $picker-ios-toolbar-height) / 2) - ($picker-ios-option-height / 2) - 10 !default;
.picker-ios .picker-wrapper {
height: $picker-ios-height;
border-top: 1px solid $picker-ios-border-color;
background: $picker-ios-background-color;
}
.picker-ios .picker-toolbar {
display: flex;
height: $picker-ios-toolbar-height;
border-bottom: $hairlines-width solid $picker-ios-border-color;
background: $picker-ios-toolbar-background-color;
}
.picker-ios .picker-toolbar-button {
@include text-align(end);
flex: 1;
}
.picker-ios .picker-toolbar-button:last-child .picker-button {
font-weight: $picker-ios-button-strong-font-weight;
}
.picker-ios .picker-toolbar-cancel {
@include text-align(start);
font-weight: normal;
}
.picker-ios .picker-button,
.picker-ios .picker-button.activated {
@include margin(0);
@include padding($picker-ios-button-padding-top, $picker-ios-button-padding-end, $picker-ios-button-padding-bottom, $picker-ios-button-padding-start);
height: $picker-ios-button-height;
color: $picker-ios-button-text-color;
background: $picker-ios-button-background-color;
font-size: $picker-ios-button-font-size;
}
.picker-columns {
height: $picker-ios-height - $picker-ios-toolbar-height - 1;
perspective: $picker-ios-column-perspective;
}
.picker-ios .picker-col {
@include padding($picker-ios-column-padding-top, $picker-ios-column-padding-end, $picker-ios-column-padding-bottom, $picker-ios-column-padding-start);
transform-style: preserve-3d;
}
.picker-ios .picker-prefix,
.picker-ios .picker-suffix,
.picker-ios .picker-opts {
top: $picker-ios-option-offset-y;
font-size: $picker-ios-option-font-size;
line-height: $picker-ios-option-height;
color: $picker-ios-option-text-color;
transform-style: preserve-3d;
pointer-events: none;
}
.picker-ios .picker-opt {
@include margin(0);
@include transform-origin(center, center);
height: 4.6rem;
font-size: $picker-ios-option-font-size;
line-height: $picker-ios-option-height;
color: $picker-ios-option-text-color;
background: transparent;
transform-style: preserve-3d;
transition-timing-function: ease-out;
backface-visibility: hidden;
pointer-events: auto;
@include padding($picker-ios-option-padding-top, $picker-ios-option-padding-end, $picker-ios-option-padding-bottom, $picker-ios-option-padding-start);
}
.picker-ios .picker-above-highlight {
@include position(0, null, null, 0);
@include transform(translate3d(0, 0, 90px));
position: absolute;
z-index: 10;
display: block;
width: 100%;
height: $picker-ios-option-offset-y + 4px;
border-bottom: 1px solid $picker-ios-border-color;
background: linear-gradient(to bottom,
rgba($picker-ios-background-color, 1) 20%,
rgba($picker-ios-background-color, .7) 100%);
}
.picker-ios .picker-below-highlight {
@include position($picker-ios-option-offset-y + $picker-ios-option-height - 4, null, null, 0);
@include transform(translate3d(0, 0, 90px));
position: absolute;
z-index: 11;
display: block;
width: 100%;
height: $picker-ios-option-offset-y + $picker-ios-option-height;
border-top: 1px solid $picker-ios-border-color;
background: linear-gradient(to top,
rgba($picker-ios-background-color, 1) 30%,
rgba($picker-ios-background-color, .7) 100%);
}

View File

@ -0,0 +1,195 @@
@import "../../themes/ionic.globals.md";
@import "./picker";
// Material Design Picker
// --------------------------------------------------
/// @prop - Height of the picker wrapper
$picker-md-height: 260px !default;
/// @prop - Border color of the picker wrapper
$picker-md-border-color: $list-md-border-color !default;
/// @prop - Background of the picker wrapper
$picker-md-background-color: $list-md-background-color !default;
/// @prop - Height of the picker toolbar
$picker-md-toolbar-height: 44px !default;
/// @prop - Background of the picker toolbar
$picker-md-toolbar-background-color: $picker-md-background-color !default;
/// @prop - Height of the picker button
$picker-md-button-height: $picker-md-toolbar-height !default;
/// @prop - Text color of the picker button
$picker-md-button-text-color: color($colors-md, primary) !default;
/// @prop - Background of the picker button
$picker-md-button-background-color: transparent !default;
/// @prop - Font size of the picker button
$picker-md-button-font-size: 1.4rem !default;
/// @prop - Padding top of the picker column
$picker-md-column-padding-top: 0 !default;
/// @prop - Padding end of the picker column
$picker-md-column-padding-end: 8px !default;
/// @prop - Padding bottom of the picker column
$picker-md-column-padding-bottom: $picker-md-column-padding-top !default;
/// @prop - Padding start of the picker column
$picker-md-column-padding-start: $picker-md-column-padding-end !default;
/// @prop - Padding top of the picker option
$picker-md-option-padding-top: 0 !default;
/// @prop - Padding end of the picker option
$picker-md-option-padding-end: $picker-md-option-padding-top !default;
/// @prop - Padding bottom of the picker option
$picker-md-option-padding-bottom: $picker-md-option-padding-top !default;
/// @prop - Padding start of the picker option
$picker-md-option-padding-start: $picker-md-option-padding-end !default;
/// @prop - Text color of the picker option
$picker-md-option-text-color: $list-md-text-color !default;
/// @prop - Font size of the picker option
$picker-md-option-font-size: 22px !default;
/// @prop - Height of the picker option
$picker-md-option-height: 42px !default;
/// @prop - Offset y of the picker option
$picker-md-option-offset-y: (($picker-md-height - $picker-md-toolbar-height) / 2) - ($picker-md-option-height / 2) - 10 !default;
/// @prop - Text color of the selected picker option
$picker-md-option-selected-color: color($colors-md, primary) !default;
.picker-md .picker-wrapper {
height: $picker-md-height;
border-top: $hairlines-width solid $picker-md-border-color;
background: $picker-md-background-color;
}
.picker-md .picker-toolbar {
display: flex;
justify-content: flex-end;
height: $picker-md-toolbar-height;
background: $picker-md-toolbar-background-color;
}
.picker-md .picker-button,
.picker-md .picker-button.activated {
@include margin(0);
height: $picker-md-button-height;
color: $picker-md-button-text-color;
background: $picker-md-button-background-color;
font-size: $picker-md-button-font-size;
font-weight: 500;
text-transform: uppercase;
padding: 0 1.1em;
box-shadow: none;
}
.picker-md .picker-columns {
height: $picker-md-height - $picker-md-toolbar-height;
perspective: 1800px;
}
.picker-md .picker-col {
@include padding($picker-md-column-padding-top, $picker-md-column-padding-end, $picker-md-column-padding-bottom, $picker-md-column-padding-start);
transform-style: preserve-3d;
}
.picker-md .picker-prefix,
.picker-md .picker-suffix,
.picker-md .picker-opts {
top: $picker-md-option-offset-y;
font-size: $picker-md-option-font-size;
line-height: $picker-md-option-height;
color: $picker-md-option-text-color;
transform-style: preserve-3d;
pointer-events: none;
}
.picker-md .picker-opt {
@include margin(0);
@include padding($picker-md-option-padding-top, $picker-md-option-padding-end, $picker-md-option-padding-bottom, $picker-md-option-padding-start);
height: 4.3rem;
font-size: $picker-md-option-font-size;
line-height: $picker-md-option-height;
color: $picker-md-option-text-color;
background: transparent;
transition-timing-function: ease-out;
backface-visibility: hidden;
pointer-events: auto;
}
.picker-md .picker-prefix,
.picker-md .picker-suffix,
.picker-md .picker-opt.picker-opt-selected {
color: $picker-md-option-selected-color;
}
.picker-md .picker-above-highlight {
@include position(0, null, null, 0);
@include transform(translate3d(0, 0, 90px));
position: absolute;
z-index: 10;
width: 100%;
height: $picker-md-option-offset-y + 4px;
border-bottom: 1px solid $picker-md-border-color;
background: linear-gradient(to bottom,
rgba($picker-md-background-color, 1) 20%,
rgba($picker-md-background-color, .7) 100%);
}
.picker-md .picker-below-highlight {
@include position($picker-md-option-offset-y + $picker-md-option-height - 4, null, null, 0);
@include transform(translate3d(0, 0, 90px));
position: absolute;
z-index: 11;
width: 100%;
height: $picker-md-option-offset-y + $picker-md-option-height;
border-top: 1px solid $picker-md-border-color;
background: linear-gradient(to top,
rgba($picker-md-background-color, 1) 30%,
rgba($picker-md-background-color, .7) 100%);
}

View File

@ -0,0 +1,169 @@
@import "../../themes/ionic.globals";
// Picker
// --------------------------------------------------
/// @prop - Width of the picker
$picker-width: 100% !default;
/// @prop - Max width of the picker
$picker-max-width: 500px !default;
ion-picker {
@include position(0, null, null, 0);
position: absolute;
z-index: $z-index-overlay;
display: block;
width: $picker-width;
height: $picker-width;
contain: strict;
}
.picker-toolbar {
z-index: 1;
width: 100%;
contain: strict;
}
.picker-wrapper {
@include position(null, 0, 0, 0);
@include margin(auto);
@include transform(translate3d(0, 100%, 0));
position: absolute;
z-index: $z-index-overlay-wrapper;
display: flex;
overflow: hidden;
flex-direction: column;
width: $picker-width;
max-width: $picker-max-width;
contain: strict;
}
.picker-columns {
position: relative;
display: flex;
overflow: hidden;
justify-content: center;
contain: strict;
@include rtl() {
// Date is the same format in both directions
flex-direction: row-reverse;
}
}
.picker-col {
position: relative;
display: flex;
flex: 1;
justify-content: center;
height: 100%;
box-sizing: content-box;
contain: content;
}
.picker-opts {
position: relative;
flex: 1;
max-width: 100%;
}
.picker-prefix {
@include text-align(end);
position: relative;
flex: 2;
min-width: 45%;
max-width: 50%;
white-space: nowrap;
}
.picker-suffix {
@include text-align(start);
position: relative;
flex: 2;
min-width: 45%;
max-width: 50%;
white-space: nowrap;
}
// contain property is supported by Chrome
.picker-opt {
@include position(0, null, null, 0);
@include text-align(center);
position: absolute;
display: block;
overflow: hidden;
width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
will-change: transform;
contain: strict;
}
.picker-opt.picker-opt-disabled {
pointer-events: none;
}
.picker-opt-disabled {
opacity: 0;
}
.picker-opts-left {
@include ltr() {
justify-content: flex-start;
}
@include rtl() {
justify-content: flex-end;
}
}
.picker-opts-right {
@include ltr() {
justify-content: flex-end;
}
@include rtl() {
justify-content: flex-start;
}
}
.picker-above-highlight,
.picker-below-highlight {
display: none;
pointer-events: none;
}

View File

@ -0,0 +1,603 @@
import { Animation, AnimationBuilder, AnimationController, Config } from '../../index';
import { Component, CssClassMap, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
import iOSEnterAnimation from './animations/ios.enter';
import iOSLeaveAnimation from './animations/ios.leave';
@Component({
tag: 'ion-picker',
styleUrls: {
ios: 'picker.ios.scss',
md: 'picker.md.scss',
wp: 'picker.wp.scss'
},
host: {
theme: 'picker'
}
})
export class Picker {
private animation: Animation;
private durationTimeout: any;
private mode: string;
@Element() private el: HTMLElement;
@Event() private ionPickerDidLoad: EventEmitter;
@Event() private ionPickerDidPresent: EventEmitter;
@Event() private ionPickerWillPresent: EventEmitter;
@Event() private ionPickerWillDismiss: EventEmitter;
@Event() private ionPickerDidDismiss: EventEmitter;
@Event() private ionPickerDidUnload: EventEmitter;
@State() private showSpinner: boolean = null;
@State() private spinner: string;
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: AnimationController;
@Prop({ context: 'config' }) config: Config;
@Prop() cssClass: string;
@Prop() content: string;
@Prop() dismissOnPageChange: boolean = false;
@Prop() duration: number;
@Prop() enterAnimation: AnimationBuilder;
@Prop() exitAnimation: AnimationBuilder;
@Prop() id: string;
@Prop() showBackdrop: boolean = true;
@Prop() enableBackdropDismiss: boolean = true;
@Prop() buttons: PickerButton[] = [];
@Prop() columns: PickerColumn[] = [];
present() {
return new Promise<void>(resolve => {
this._present(resolve);
});
}
private _present(resolve: Function) {
if (this.animation) {
this.animation.destroy();
this.animation = null;
}
this.ionPickerWillPresent.emit({ picker: this });
// get the user's animation fn if one was provided
let animationBuilder = this.enterAnimation;
if (!animationBuilder) {
// user did not provide a custom animation fn
// decide from the config which animation to use
animationBuilder = iOSEnterAnimation;
}
// build the animation and kick it off
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
this.animation = animation;
animation.onFinish((a: any) => {
a.destroy();
this.ionViewDidEnter();
resolve();
}).play();
});
}
dismiss() {
clearTimeout(this.durationTimeout);
if (this.animation) {
this.animation.destroy();
this.animation = null;
}
return new Promise(resolve => {
this.ionPickerWillDismiss.emit({ picker: this });
// get the user's animation fn if one was provided
let animationBuilder = this.exitAnimation;
if (!animationBuilder) {
// user did not provide a custom animation fn
// decide from the config which animation to use
animationBuilder = iOSLeaveAnimation;
}
// build the animation and kick it off
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
this.animation = animation;
animation.onFinish((a: any) => {
a.destroy();
this.ionPickerDidDismiss.emit({ picker: this });
Context.dom.write(() => {
this.el.parentNode.removeChild(this.el);
});
resolve();
}).play();
});
});
}
protected ionViewDidUnload() {
this.ionPickerDidUnload.emit({ picker: this });
}
@Listen('ionDismiss')
protected onDismiss(ev: UIEvent) {
ev.stopPropagation();
ev.preventDefault();
this.dismiss();
}
protected ionViewDidLoad() {
if (!this.spinner) {
let defaultSpinner = 'lines';
if (this.mode === 'md') {
defaultSpinner = 'crescent';
} else if (this.mode === 'wp') {
defaultSpinner = 'circles';
}
this.spinner = this.config.get('pickerSpinner') || defaultSpinner;
}
if (this.showSpinner === null || this.showSpinner === undefined) {
this.showSpinner = !!(this.spinner && this.spinner !== 'hide');
}
this.ionPickerDidLoad.emit({ picker: this });
}
protected ionViewDidEnter() {
// blur the currently active element
const activeElement: any = document.activeElement;
activeElement && activeElement.blur && activeElement.blur();
// If there is a duration, dismiss after that amount of time
if (typeof this.duration === 'number' && this.duration > 10) {
this.durationTimeout = setTimeout(() => this.dismiss(), this.duration);
}
this.ionPickerDidPresent.emit({ picker: this });
}
btnClick(button: PickerButton) {
// if (!this.enabled) {
// return;
// }
// // keep the time of the most recent button click
// this.lastClick = Date.now();
let shouldDismiss = true;
// if (button.handler) {
// // a handler has been provided, execute it
// // pass the handler the values from the inputs
// if (button.handler(this.getSelected()) === false) {
// // if the return value of the handler is false then do not dismiss
// shouldDismiss = false;
// }
// }
if (shouldDismiss) {
this.dismiss();
}
}
/**
* @param {PickerColumn} column Picker toolbar button
*/
@Method()
addColumn(column: PickerColumn) {
this.columns.push(column);
}
@Method()
getColumn(name: string): PickerColumn {
return this.getColumns().find(column => column.name === name);
}
@Method()
getColumns(): PickerColumn[] {
return this.columns;
}
protected backdropClick() {
// TODO this.enabled
if (this.enableBackdropDismiss) {
let cancelBtn = this.buttons.find(b => b.role === 'cancel');
if (cancelBtn) {
this.btnClick(cancelBtn);
} else {
this.dismiss();
}
}
}
protected render() {
let userCssClass = 'picker-content';
if (this.cssClass) {
userCssClass += ' ' + this.cssClass;
}
let buttons = this.buttons
.map(b => {
if (typeof b === 'string') {
b = { text: b };
}
if (!b.cssClass) {
b.cssClass = '';
}
return b;
})
.filter(b => b !== null);
console.log('picker render, columns', this.columns);
let columns = this.columns;
return [
<ion-backdrop
onClick={this.backdropClick.bind(this)}
class={{
'picker-backdrop': true,
'hide-backdrop': !this.showBackdrop
}}
/>,
<div class='picker-wrapper' role='dialog'>
<div class='picker-toolbar'>
{buttons.map(b =>
<div class={this.buttonWrapperClass(b)}>
<button onClick={() => this.btnClick(b)} class={this.buttonClass(b)}>
{b.text}
</button>
</div>
)}
</div>
<div class="picker-columns">
<div class="picker-above-highlight"></div>
{columns.map(c =>
<ion-picker-column col={c}></ion-picker-column>
)}
<div class="picker-below-highlight"></div>
</div>
</div>
];
}
buttonWrapperClass(button: PickerButton): CssClassMap {
console.log('buttonWrapperClass', button);
let buttonClass: string[] = !button.role
? ['picker-toolbar-button']
: [`picker-toolbar-button`, `picker-toolbar-${button.role}`];
return buttonClass.reduce((prevValue: any, cssClass: any) => {
prevValue[cssClass] = true;
return prevValue;
}, {});
}
buttonClass(button: PickerButton): CssClassMap {
let buttonClass: string[] = !button.cssClass
? ['picker-button']
: [`picker-button`, `${button.cssClass}`];
return buttonClass.reduce((prevValue: any, cssClass: any) => {
prevValue[cssClass] = true;
return prevValue;
}, {});
}
}
export interface PickerButton {
text?: string;
role?: string;
cssClass?: string;
handler?: (value: any) => boolean|void;
}
export interface PickerOptions {
buttons?: PickerButton[];
columns?: PickerColumn[];
cssClass?: string;
enableBackdropDismiss?: boolean;
}
export interface PickerColumn {
name?: string;
align?: string;
selectedIndex?: number;
prevSelected?: number;
prefix?: string;
suffix?: string;
options?: PickerColumnOption[];
cssClass?: string;
columnWidth?: string;
prefixWidth?: string;
suffixWidth?: string;
optionsWidth?: string;
}
export interface PickerColumnOption {
text?: string;
value?: any;
disabled?: boolean;
}
export interface PickerEvent extends Event {
detail: {
picker: Picker;
};
}
export const PICKER_OPT_SELECTED = 'picker-opt-selected';
export const DECELERATION_FRICTION = 0.97;
export const FRAME_MS = (1000 / 60);
export const MAX_PICKER_SPEED = 60;
// /**
// * @hidden
// */
// @Component({
// selector: 'ion-picker-cmp',
// template: `
// <ion-backdrop (click)="bdClick()"></ion-backdrop>
// <div class="picker-wrapper">
// <div class="picker-toolbar">
// <div *ngFor="let b of d.buttons" class="picker-toolbar-button" [ngClass]="b.cssRole">
// <ion-button (click)="btnClick(b)" [ngClass]="b.cssClass" class="picker-button" clear>
// {{b.text}}
// </ion-button>
// </div>
// </div>
// <div class="picker-columns">
// <div class="picker-above-highlight"></div>
// <div *ngFor="let c of d.columns" [col]="c" class="picker-col" (ionChange)="_colChange($event)"></div>
// <div class="picker-below-highlight"></div>
// </div>
// </div>
// `,
// host: {
// 'role': 'dialog'
// },
// encapsulation: ViewEncapsulation.None,
// })
// export class PickerCmp {
// @ViewChildren(PickerColumnCmp) _cols: QueryList<PickerColumnCmp>;
// d: PickerOptions;
// enabled: boolean;
// lastClick: number;
// id: number;
// mode: string;
// _gestureBlocker: BlockerDelegate;
// constructor(
// private _viewCtrl: ViewController,
// private _elementRef: ElementRef,
// config: Config,
// private _plt: Platform,
// gestureCtrl: GestureController,
// params: NavParams,
// renderer: Renderer
// ) {
// this._gestureBlocker = gestureCtrl.createBlocker(BLOCK_ALL);
// this.d = params.data;
// this.mode = config.get('mode');
// renderer.setElementClass(_elementRef.nativeElement, `picker-${this.mode}`, true);
// if (this.d.cssClass) {
// this.d.cssClass.split(' ').forEach(cssClass => {
// renderer.setElementClass(_elementRef.nativeElement, cssClass, true);
// });
// }
// this.id = (++pickerIds);
// this.lastClick = 0;
// }
// ionViewWillLoad() {
// // normalize the data
// let data = this.d;
// data.buttons = data.buttons.map(button => {
// if (isString(button)) {
// return { text: button };
// }
// });
// // clean up dat data
// data.columns = data.columns.map(column => {
// if (!isPresent(column.options)) {
// column.options = [];
// }
// column.selectedIndex = column.selectedIndex || 0;
// column.options = column.options.map(inputOpt => {
// let opt: PickerColumnOption = {
// text: '',
// value: '',
// disabled: inputOpt.disabled,
// };
// if (isPresent(inputOpt)) {
// if (isString(inputOpt) || isNumber(inputOpt)) {
// opt.text = inputOpt.toString();
// opt.value = inputOpt;
// } else {
// opt.text = isPresent(inputOpt.text) ? inputOpt.text : inputOpt.value;
// opt.value = isPresent(inputOpt.value) ? inputOpt.value : inputOpt.text;
// }
// }
// return opt;
// });
// return column;
// });
// }
// ionViewDidLoad() {
// this.refresh();
// }
// ionViewWillEnter() {
// this._gestureBlocker.block();
// }
// ionViewDidLeave() {
// this._gestureBlocker.unblock();
// }
// refresh() {
// this._cols.forEach(column => column.refresh());
// }
// _colChange(selectedOption: PickerColumnOption) {
// // one of the columns has changed its selected index
// var picker = <Picker>this._viewCtrl;
// picker.ionChange.emit(this.getSelected());
// }
// @HostListener('body:keyup', ['$event'])
// _keyUp(ev: KeyboardEvent) {
// if (this.enabled && this._viewCtrl.isLast()) {
// if (ev.keyCode === KEY_ENTER) {
// if (this.lastClick + 1000 < Date.now()) {
// // do not fire this click if there recently was already a click
// // this can happen when the button has focus and used the enter
// // key to click the button. However, both the click handler and
// // this keyup event will fire, so only allow one of them to go.
// console.debug('picker, enter button');
// let button = this.d.buttons[this.d.buttons.length - 1];
// this.btnClick(button);
// }
// } else if (ev.keyCode === KEY_ESCAPE) {
// console.debug('picker, escape button');
// this.bdClick();
// }
// }
// }
// ionViewDidEnter() {
// this._plt.focusOutActiveElement();
// let focusableEle = this._elementRef.nativeElement.querySelector('button');
// if (focusableEle) {
// focusableEle.focus();
// }
// this.enabled = true;
// }
// dismiss(role: string): Promise<any> {
// return this._viewCtrl.dismiss(this.getSelected(), role);
// }
// getSelected(): any {
// let selected: {[k: string]: any} = {};
// this.d.columns.forEach((col, index) => {
// let selectedColumn = col.options[col.selectedIndex];
// selected[col.name] = {
// text: selectedColumn ? selectedColumn.text : null,
// value: selectedColumn ? selectedColumn.value : null,
// columnIndex: index,
// };
// });
// return selected;
// }
// ngOnDestroy() {
// assert(this._gestureBlocker.blocked === false, 'gesture blocker must be already unblocked');
// this._gestureBlocker.destroy();
// }
// }
// let pickerIds = -1;
// /**
// * @hidden
// */
// export class Picker extends ViewController {
// private _app: App;
// @Output() ionChange: EventEmitter<any>;
// constructor(app: App, opts: PickerOptions = {}, config: Config) {
// if (!opts) {
// opts = {};
// }
// opts.columns = opts.columns || [];
// opts.buttons = opts.buttons || [];
// opts.enableBackdropDismiss = isPresent(opts.enableBackdropDismiss) ? Boolean(opts.enableBackdropDismiss) : true;
// super(PickerCmp, opts, null);
// this._app = app;
// this.isOverlay = true;
// this.ionChange = new EventEmitter<any>();
// config.setTransition('picker-slide-in', PickerSlideIn);
// config.setTransition('picker-slide-out', PickerSlideOut);
// }
// /**
// * @hidden
// */
// getTransitionName(direction: string) {
// let key = (direction === 'back' ? 'pickerLeave' : 'pickerEnter');
// return this._nav && this._nav.config.get(key);
// }
// /**
// * @param {any} button Picker toolbar button
// */
// addButton(button: any) {
// this.data.buttons.push(button);
// }
// refresh() {
// assert(this._cmp, 'componentRef must be valid');
// assert(this._cmp.instance.refresh, 'instance must implement refresh()');
// this._cmp && this._cmp.instance.refresh && this._cmp.instance.refresh();
// }
// /**
// * @param {string} cssClass CSS class name to add to the picker's outer wrapper.
// */
// setCssClass(cssClass: string) {
// this.data.cssClass = cssClass;
// }
// /**
// * Present the picker instance.
// *
// * @param {NavOptions} [navOptions={}] Nav options to go with this transition.
// * @returns {Promise} Returns a promise which is resolved when the transition has completed.
// */
// present(navOptions: NavOptions = {}) {
// return this._app.present(this, navOptions);
// }
// }

View File

@ -0,0 +1,201 @@
@import "../../themes/ionic.globals.wp";
@import "./picker";
// Windows Picker
// --------------------------------------------------
/// @prop - Height of the picker wrapper
$picker-wp-height: 260px !default;
/// @prop - Border color of the picker wrapper
$picker-wp-border-color: $list-wp-border-color !default;
/// @prop - Background of the picker wrapper
$picker-wp-background-color: $list-wp-background-color !default;
/// @prop - Height of the picker toolbar
$picker-wp-toolbar-height: 44px !default;
/// @prop - Background of the picker toolbar
$picker-wp-toolbar-background-color: $picker-wp-background-color !default;
/// @prop - Height of the picker button
$picker-wp-button-height: $picker-wp-toolbar-height !default;
/// @prop - Text color of the picker button
$picker-wp-button-text-color: color($colors-wp, primary) !default;
/// @prop - Background of the picker button
$picker-wp-button-background-color: transparent !default;
/// @prop - Padding top of the picker column
$picker-wp-column-padding-top: 0 !default;
/// @prop - Padding end of the picker column
$picker-wp-column-padding-end: 4px !default;
/// @prop - Padding bottom of the picker column
$picker-wp-column-padding-bottom: $picker-wp-column-padding-top !default;
/// @prop - Padding start of the picker column
$picker-wp-column-padding-start: $picker-wp-column-padding-end !default;
/// @prop - Padding top of the picker option
$picker-wp-option-padding-top: 0 !default;
/// @prop - Padding end of the picker option
$picker-wp-option-padding-end: $picker-wp-option-padding-top !default;
/// @prop - Padding bottom of the picker option
$picker-wp-option-padding-bottom: $picker-wp-option-padding-top !default;
/// @prop - Padding start of the picker option
$picker-wp-option-padding-start: $picker-wp-option-padding-end !default;
/// @prop - Text color of the picker option
$picker-wp-option-text-color: $list-wp-text-color !default;
/// @prop - Font size of the picker option
$picker-wp-option-font-size: 22px !default;
/// @prop - Height of the picker option
$picker-wp-option-height: 42px !default;
/// @prop - Offset y of the picker option
$picker-wp-option-offset-y: (($picker-wp-height - $picker-wp-toolbar-height) / 2) - ($picker-wp-option-height / 2) - 10 !default;
/// @prop - Text color of the selected picker option
$picker-wp-option-selected-color: color($colors-wp, primary) !default;
.picker-wp .picker-wrapper {
height: $picker-wp-height;
border-top: $hairlines-width solid $picker-wp-border-color;
background: $picker-wp-background-color;
}
.picker-wp .picker-toolbar {
display: flex;
justify-content: flex-end;
height: $picker-wp-toolbar-height;
border-width: $hairlines-width;
background: $picker-wp-toolbar-background-color;
}
.picker-wp .picker-toolbar-button {
@include text-align(end);
flex: 1;
}
.picker-wp .picker-toolbar-cancel {
@include text-align(start);
font-weight: normal;
}
.picker-wp .picker-button,
.picker-wp .picker-button.activated {
@include margin(0);
height: $picker-wp-button-height;
color: $picker-wp-button-text-color;
background: $picker-wp-button-background-color;
box-shadow: none;
}
.picker-wp .picker-columns {
height: $picker-wp-height - $picker-wp-toolbar-height;
perspective: 1800px;
}
.picker-wp .picker-col {
@include padding($picker-wp-column-padding-top, $picker-wp-column-padding-end, $picker-wp-column-padding-bottom, $picker-wp-column-padding-start);
transform-style: preserve-3d;
}
.picker-wp .picker-prefix,
.picker-wp .picker-suffix,
.picker-wp .picker-opts {
top: $picker-wp-option-offset-y;
font-size: $picker-wp-option-font-size;
line-height: $picker-wp-option-height;
color: $picker-wp-option-text-color;
transform-style: preserve-3d;
pointer-events: none;
}
.picker-wp .picker-opt {
@include margin(0);
@include padding($picker-wp-option-padding-top, $picker-wp-option-padding-end, $picker-wp-option-padding-bottom, $picker-wp-option-padding-start);
height: 4.2rem;
font-size: $picker-wp-option-font-size;
line-height: $picker-wp-option-height;
color: $picker-wp-option-text-color;
background: transparent;
transition-timing-function: ease-out;
backface-visibility: hidden;
pointer-events: auto;
}
.picker-wp .picker-prefix,
.picker-wp .picker-suffix,
.picker-wp .picker-opt-selected {
color: $picker-wp-option-selected-color;
}
.picker-wp .picker-above-highlight {
@include position(0, null, null, 0);
@include transform(translate3d(0, 0, 90px));
position: absolute;
z-index: 10;
width: 100%;
height: $picker-wp-option-offset-y + 4px;
border-bottom: 1px solid $picker-wp-border-color;
background: linear-gradient(to bottom,
rgba($picker-wp-background-color, 1) 20%,
rgba($picker-wp-background-color, .7) 100%);
}
.picker-wp .picker-below-highlight {
@include position($picker-wp-option-offset-y + $picker-wp-option-height - 4, null, null, 0);
@include transform(translate3d(0, 0, 90px));
position: absolute;
z-index: 11;
width: 100%;
height: $picker-wp-option-offset-y + $picker-wp-option-height;
border-top: 1px solid $picker-wp-border-color;
background: linear-gradient(to top,
rgba($picker-wp-background-color, 1) 30%,
rgba($picker-wp-background-color, .7) 100%);
}

View File

@ -14,6 +14,9 @@ import { MenuController } from './components/menu/menu-controller';
import { Modal, ModalOptions, ModalEvent } from './components/modal/modal';
import { ModalController } from './components/modal-controller/modal-controller';
import { Picker, PickerButton, PickerColumn, PickerEvent, PickerOptions } from './components/picker/picker'
import { PickerController } from './components/picker-controller/picker-controller'
import { Popover, PopoverEvent, PopoverOptions } from './components/popover/popover'
import { PopoverController } from './components/popover-controller/popover-controller'
@ -82,6 +85,12 @@ export {
ModalController,
ModalOptions,
ModalEvent,
Picker,
PickerButton,
PickerColumn,
PickerController,
PickerEvent,
PickerOptions,
Popover,
PopoverController,
PopoverEvent,