Merge branch 'mono-refactor' into core/overlay

This commit is contained in:
Brandy Carney
2017-08-11 13:54:37 -04:00
30 changed files with 1103 additions and 224 deletions

View File

@ -1,34 +1,34 @@
{ {
"name": "@ionic/core", "name": "@ionic/core",
"version": "0.0.2-3", "version": "0.0.2-4",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@stencil/core": { "@stencil/core": {
"version": "0.0.4-4", "version": "0.0.4-11",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-0.0.4-4.tgz", "resolved": "https://registry.npmjs.org/@stencil/core/-/core-0.0.4-11.tgz",
"integrity": "sha512-fcFq1gNxrpIvZu1M7J+9E8mT7Rd2LW2nhKdVkJCxYdQs7UErVyn5ksY0Ckqgvsn0wOPaymUoeNkYAcG/L7sTRQ==", "integrity": "sha512-CJo2o3RAnzA84AZ0GXMH0TANZR/z6JH1EKd+hnXwnu62CH+KZ37zjEXrMy5tsRCJ1nfqSwS6BOwAJtV1+xoeVA==",
"requires": { "requires": {
"chalk": "1.1.3", "chalk": "1.1.3",
"chokidar": "1.7.0", "chokidar": "1.7.0",
"clean-css": "4.1.7", "clean-css": "4.1.7",
"jsdom": "11.1.0", "jsdom": "11.1.0",
"node-fetch": "1.7.1", "node-fetch": "1.7.2",
"node-sass": "4.5.3", "node-sass": "4.5.3",
"rollup": "0.41.4", "rollup": "0.41.4",
"rollup-plugin-commonjs": "8.1.0", "rollup-plugin-commonjs": "8.1.0",
"rollup-plugin-node-resolve": "3.0.0", "rollup-plugin-node-resolve": "3.0.0",
"typescript": "2.4.0", "typescript": "2.5.0-dev.20170808",
"uglify-es": "3.0.27" "uglify-es": "3.0.27"
} }
}, },
"@stencil/dev-server": { "@stencil/dev-server": {
"version": "0.0.11", "version": "0.0.14",
"resolved": "https://registry.npmjs.org/@stencil/dev-server/-/dev-server-0.0.11.tgz", "resolved": "https://registry.npmjs.org/@stencil/dev-server/-/dev-server-0.0.14.tgz",
"integrity": "sha512-ZNPsLAxhP5e5SUdEpPZm/mlcRTDHSGctY9CsChncisMm0zjYeKNQFqel+ZKAO8sIdmikQDyCDuZwq2JEMneTwg==", "integrity": "sha512-sdnuZ1Tgg1I8DsXhkzyZjrwdFkQvI0HrXQXcHARZYeV6CeIJS51+q9EbvoMBHsUBuqPxgTgR8GHySw/DfZY5UQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"chalk": "2.0.1", "chalk": "2.1.0",
"chokidar": "1.7.0", "chokidar": "1.7.0",
"ecstatic": "2.2.1", "ecstatic": "2.2.1",
"lodash.debounce": "4.0.8", "lodash.debounce": "4.0.8",
@ -46,9 +46,9 @@
} }
}, },
"chalk": { "chalk": {
"version": "2.0.1", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
"integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"ansi-styles": "3.2.0", "ansi-styles": "3.2.0",
@ -2141,9 +2141,9 @@
"integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=" "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U="
}, },
"node-fetch": { "node-fetch": {
"version": "1.7.1", "version": "1.7.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.2.tgz",
"integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ==", "integrity": "sha512-xZZUq2yDhKMIn/UgG5q//IZSNLJIwW2QxS14CNH5spuiXkITM2pUitjdq58yLSaU7m4M0wBNaM2Gh/ggY4YJig==",
"requires": { "requires": {
"encoding": "0.1.12", "encoding": "0.1.12",
"is-stream": "1.1.0" "is-stream": "1.1.0"
@ -2959,9 +2959,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "2.4.0", "version": "2.5.0-dev.20170808",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.0.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.0-dev.20170808.tgz",
"integrity": "sha1-rvWo1AS+ujatM5q/B53d3/+6ht0=" "integrity": "sha512-Gb+2vCDs47CMtRzpoc41Uia4UDV4biDYZo9Z5nTwINftcI96FecFCQgJQAMLF8G4bKR4pwKmOuiSN1JyGInN3A=="
}, },
"uglify-es": { "uglify-es": {
"version": "3.0.27", "version": "3.0.27",

View File

@ -1,6 +1,6 @@
{ {
"name": "@ionic/core", "name": "@ionic/core",
"version": "0.0.2-3", "version": "0.0.2-4",
"description": "Base components for Ionic", "description": "Base components for Ionic",
"main": "dist/collection/index.js", "main": "dist/collection/index.js",
"types": "dist/collection/index.d.ts", "types": "dist/collection/index.d.ts",
@ -10,16 +10,16 @@
"README.md" "README.md"
], ],
"dependencies": { "dependencies": {
"@stencil/core": "^0.0.4-3" "@stencil/core": "0.0.4-14"
}, },
"devDependencies": { "devDependencies": {
"@stencil/dev-server": "^0.0.11", "@stencil/dev-server": "latest",
"@stencil/utils": "^0.0.4" "@stencil/utils": "latest"
}, },
"scripts": { "scripts": {
"build": "stencil build", "build": "stencil build",
"dev": "sd concurrent \"stencil build --dev --watch\" \"stencil-dev-server\"", "dev": "sd concurrent \"stencil build --dev --watch\" \"stencil-dev-server\"",
"publish": "../../node_modules/.bin/np --any-branch", "publish": "npm run build && node scripts/publish.js && node scripts/publish.js && ../../node_modules/.bin/np --any-branch",
"test": "(jest --no-cache || true)" "test": "(jest --no-cache || true)"
}, },
"author": "Ionic Team", "author": "Ionic Team",

View File

@ -0,0 +1,17 @@
var fs = require('fs');
var path = require('path');
var DIST = path.join(__dirname, '../dist/collection');
var SRC = path.join(__dirname, '../src');
var INDEX_JS_DIST = path.join(DIST, 'index.js');
var INDEX_DTS_SRC = path.join(SRC, 'index.d.ts');
var INDEX_DTS_DIST = path.join(DIST, 'index.d.ts');
console.log('publish: create', INDEX_JS_DIST);
fs.writeFileSync(INDEX_JS_DIST, '');
console.log('publish: create', INDEX_DTS_DIST);
var srcIndexDTS = fs.readFileSync(INDEX_DTS_SRC, 'utf-8');
fs.writeFileSync(INDEX_DTS_DIST, srcIndexDTS);

View File

@ -1,5 +1,7 @@
import { Component, Element, Prop, CssClassMap } from '@stencil/core'; import { Component, Element, Prop, CssClassMap } from '@stencil/core';
import { getElementClassObject } from '../../utils/theme';
/** /**
* @name Button * @name Button
* @module ionic * @module ionic
@ -178,7 +180,9 @@ export class Button {
const decorator = (this.strong ? 'strong' : null); const decorator = (this.strong ? 'strong' : null);
const buttonClasses: CssClassMap = [] const hostClasses = getElementClassObject(this.el.classList);
const elementClasses: CssClassMap = []
.concat( .concat(
getButtonClassList(buttonType, mode), getButtonClassList(buttonType, mode),
getClassList(buttonType, shape, mode), getClassList(buttonType, shape, mode),
@ -186,8 +190,7 @@ export class Button {
getClassList(buttonType, size, mode), getClassList(buttonType, size, mode),
getClassList(buttonType, decorator, mode), getClassList(buttonType, decorator, mode),
getStyleClassList(mode, this.color, buttonType, this.outline, this.clear, this.solid), getStyleClassList(mode, this.color, buttonType, this.outline, this.clear, this.solid),
getItemClassList(this.itemButton, size), getItemClassList(this.itemButton, size)
getElementClassList(this.el.classList)
) )
.reduce((prevValue, cssClass) => { .reduce((prevValue, cssClass) => {
prevValue[cssClass] = true; prevValue[cssClass] = true;
@ -196,6 +199,11 @@ export class Button {
const TagType = this.href ? 'a' : 'button'; const TagType = this.href ? 'a' : 'button';
const buttonClasses = {
...hostClasses,
...elementClasses
}
return ( return (
<TagType class={buttonClasses} disabled={this.disabled}> <TagType class={buttonClasses} disabled={this.disabled}>
<span class='button-inner'> <span class='button-inner'>
@ -292,14 +300,3 @@ function getStyleClassList(mode: string, color: string, buttonType: string, outl
function getItemClassList(itemButton: boolean, size: string) { function getItemClassList(itemButton: boolean, size: string) {
return itemButton && !size ? ['item-button'] : []; return itemButton && !size ? ['item-button'] : [];
} }
/**
* Get the element classes to add to the child element
*/
function getElementClassList(elmClassList: DOMTokenList) {
const classList: string[] = [];
for (var i = 0; i < elmClassList.length; i++) {
classList.push(elmClassList.item(i));
}
return classList;
}

View File

@ -1,5 +1,6 @@
import { Component, CssClassMap, Element, Prop } from '@stencil/core'; import { Component, CssClassMap, Element, Prop } from '@stencil/core';
import { getElementClassObject } from '../../utils/theme';
@Component({ @Component({
tag: 'ion-chip-button', tag: 'ion-chip-button',
@ -71,25 +72,14 @@ export class ChipButton {
return classList; return classList;
} }
/**
* @hidden
* Get the element classes to add to the child element
*/
private getElementClassList() {
let classList = [].concat(
this.el.className.length ? this.el.className.split(' ') : []
);
return classList;
}
render() { render() {
const buttonType = 'chip-button'; const buttonType = 'chip-button';
var buttonClasses: CssClassMap = [] const hostClasses = getElementClassObject(this.el.classList);
const elementClasses: CssClassMap = []
.concat( .concat(
this.getButtonClassList(buttonType, this.mode), this.getButtonClassList(buttonType, this.mode),
this.getElementClassList(),
this.getStyleClassList(buttonType) this.getStyleClassList(buttonType)
) )
.reduce((prevValue, cssClass) => { .reduce((prevValue, cssClass) => {
@ -99,6 +89,11 @@ export class ChipButton {
const TagType = this.href ? 'a' : 'button'; const TagType = this.href ? 'a' : 'button';
const buttonClasses = {
...hostClasses,
...elementClasses
}
return ( return (
<TagType class={buttonClasses} disabled={this.disabled}> <TagType class={buttonClasses} disabled={this.disabled}>
<span class='button-inner'> <span class='button-inner'>

View File

@ -76,7 +76,7 @@
<ion-chip id="chip1"> <ion-chip id="chip1">
<ion-label>Default</ion-label> <ion-label>Default</ion-label>
<ion-chip-button clear onclick="del('chip1')"> <ion-chip-button clear onclick="del('chip1')" class="my-custom-chip">
<ion-icon name="close-circle"></ion-icon> <ion-icon name="close-circle"></ion-icon>
</ion-chip-button> </ion-chip-button>
</ion-chip> </ion-chip>

View File

@ -1,6 +1,6 @@
import { Component, Element, Prop } from '@stencil/core'; import { Component, Element, Prop } from '@stencil/core';
import { Config, Scroll, ScrollDetail } from '../../index'; import { Config, Scroll, ScrollDetail } from '../../index';
import { createThemedClasses } from '../../utils/theme'; import { createThemedClasses, getElementClassObject } from '../../utils/theme';
import { getParentElement, getToolbarHeight } from '../../utils/helpers'; import { getParentElement, getToolbarHeight } from '../../utils/helpers';
@ -103,11 +103,18 @@ export class Content {
if (this.ionScrollEnd) { if (this.ionScrollEnd) {
props['ionScrollEnd'] = this.ionScrollEnd.bind(this); props['ionScrollEnd'] = this.ionScrollEnd.bind(this);
} }
const themedClasses = createThemedClasses(this.mode, this.color, 'content'); const themedClasses = createThemedClasses(this.mode, this.color, 'content');
themedClasses['statusbar-padding'] = this.config.getBoolean('statusbarPadding'); const hostClasses = getElementClassObject(this.el.classList);
const scrollClasses = {
...themedClasses,
...hostClasses,
'statusbar-padding': this.config.getBoolean('statusbarPadding')
}
return ( return (
<ion-scroll style={scrollStyle} props={props} class={themedClasses}> <ion-scroll style={scrollStyle} props={props} class={scrollClasses}>
<slot></slot> <slot></slot>
</ion-scroll> </ion-scroll>
); );

View File

@ -1,5 +1,5 @@
import { Component, Element, CssClassMap, Method, Prop, State } from '@stencil/core'; import { Component, Element, CssClassMap, Method, Prop, State } from '@stencil/core';
import { createThemedClasses } from '../../utils/theme'; import { createThemedClasses, getElementClassObject } from '../../utils/theme';
/** /**
@ -110,18 +110,6 @@ export class FabButton {
this.setActiveLists(false); this.setActiveLists(false);
} }
/**
* @hidden
* Get the element classes to add to the child element
*/
getElementClassList() {
let classList = [].concat(
this.el.className.length ? this.el.className.split(' ') : []
);
return classList;
}
/** /**
* @hidden * @hidden
* Get the classes for fab buttons in lists * Get the classes for fab buttons in lists
@ -164,10 +152,10 @@ export class FabButton {
render() { render() {
const themedClasses = createThemedClasses(this.mode, this.color, 'fab'); const themedClasses = createThemedClasses(this.mode, this.color, 'fab');
const hostClasses = getElementClassObject(this.el.classList);
var fabClasses: CssClassMap = [] const elementClasses: CssClassMap = []
.concat( .concat(
this.getElementClassList(),
this.getFabListClassList(), this.getFabListClassList(),
this.getFabActiveClassList(), this.getFabActiveClassList(),
this.getFabShowClassList() this.getFabShowClassList()
@ -179,7 +167,11 @@ export class FabButton {
const TagType = this.href ? 'a' : 'button'; const TagType = this.href ? 'a' : 'button';
fabClasses = Object.assign(fabClasses, themedClasses); const fabClasses = {
...themedClasses,
...hostClasses,
...elementClasses
}
return ( return (
<TagType class={fabClasses} onClick={this.clickedFab.bind(this)} disabled={this.disabled}> <TagType class={fabClasses} onClick={this.clickedFab.bind(this)} disabled={this.disabled}>

View File

@ -19,7 +19,7 @@ export class Icon {
/** /**
* @input {string} Specifies the label to use for accessibility. Defaults to the icon name. * @input {string} Specifies the label to use for accessibility. Defaults to the icon name.
*/ */
@State() ariaLabel: string = ''; @Prop() ariaLabel: string = '';
/** /**
* @input {string} Specifies which icon to use. The appropriate icon will be used based on the mode. * @input {string} Specifies which icon to use. The appropriate icon will be used based on the mode.
@ -38,20 +38,13 @@ export class Icon {
@Prop() md: string = ''; @Prop() md: string = '';
@State() svgContent: string = null; @Prop({ context: 'isServer'}) private isServer: boolean;
getSvgUrl() { @State() private svgContent: string = null;
const iconName = this.iconName;
if (iconName !== null) {
return `${publicPath}svg/${iconName}.svg`;
}
return null;
}
get iconName() { private get iconName() {
// if no name was passed set iconName to null // if no name was passed set iconName to null
if (!this.name) { if (!this.name) {
return null; return null;
@ -117,21 +110,63 @@ export class Icon {
} }
static loadSvgContent(svgUrl: string, callback: {(loadedSvgContent: string): void}) { render() {
if (this.isServer) {
return <div class="icon-inner">{/* ssr */}</div>;
}
const svgUrl = getSvgUrl(this.iconName);
if (!svgUrl) {
// we don't have good data
return <div class="icon-inner">{/* invalid svg */}</div>;
}
const svgContent = svgContents[svgUrl];
if (svgContent === this.svgContent) {
// we've already loaded up this svg at one point
// and the svg content we've loaded and assigned checks out
// render this svg!!
return <div class="icon-inner" innerHTML={svgContent}></div>;
}
// haven't loaded this svg yet
// start the request
loadSvgContent(svgUrl, loadedSvgContent => {
// we're finished loading the svg content!
// set to this.svgContent so we do another render
this.svgContent = loadedSvgContent;
});
// actively requesting the svg, so let's just render a div for now
return <div class="icon-inner">{/* loading svg */}</div>;
}
}
function getSvgUrl(iconName: string) {
if (iconName !== null) {
return `${publicPath}svg/${iconName}.svg`;
}
return null;
}
function loadSvgContent(svgUrl: string, callback: {(loadedSvgContent: string): void}) {
// static since all IonIcons use this same function and pointing at global/shared data // static since all IonIcons use this same function and pointing at global/shared data
// passed in callback will have instance info // passed in callback will have instance info
// add to the list of callbacks to fiure when this url is finished loading // add to the list of callbacks to fiure when this url is finished loading
IonIcon.loadCallbacks[svgUrl] = IonIcon.loadCallbacks[svgUrl] || []; loadCallbacks[svgUrl] = loadCallbacks[svgUrl] || [];
IonIcon.loadCallbacks[svgUrl].push(callback); loadCallbacks[svgUrl].push(callback);
if (IonIcon.activeRequests[svgUrl]) { if (activeRequests[svgUrl]) {
// already requesting this url, don't bother again kicking off another // already requesting this url, don't bother again kicking off another
return; return;
} }
// add this url to our list of active requests // add this url to our list of active requests
IonIcon.activeRequests[svgUrl] = true; activeRequests[svgUrl] = true;
// kick off the request for the external svg file // kick off the request for the external svg file
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
@ -139,7 +174,7 @@ export class Icon {
// awesome, we've finished loading the svg file // awesome, we've finished loading the svg file
// remove this url from the active requests // remove this url from the active requests
delete IonIcon.activeRequests[svgUrl]; delete activeRequests[svgUrl];
// this response is the content of the svg file we're looking for // this response is the content of the svg file we're looking for
let svgContent = this.responseText; let svgContent = this.responseText;
@ -151,17 +186,17 @@ export class Icon {
} }
// cache the svg content in the global IonIcon constant // cache the svg content in the global IonIcon constant
IonIcon.svgContents[svgUrl] = svgContent; svgContents[svgUrl] = svgContent;
// find any callbacks waiting on this url // find any callbacks waiting on this url
const svgLoadCallbacks = IonIcon.loadCallbacks[svgUrl]; const svgLoadCallbacks = loadCallbacks[svgUrl];
if (svgLoadCallbacks) { if (svgLoadCallbacks) {
// loop through all the callbacks that are waiting on the svg content // loop through all the callbacks that are waiting on the svg content
for (var i = 0; i < svgLoadCallbacks.length; i++) { svgLoadCallbacks.forEach(cb => {
// fire off this callback which was provided by an instance // fire off this callback which was provided by an instance
svgLoadCallbacks[i](svgContent); cb(svgContent);
} });
delete IonIcon.loadCallbacks[svgUrl]; delete loadCallbacks[svgUrl];
} }
}); });
@ -176,45 +211,6 @@ export class Icon {
} }
render() { const activeRequests: {[url: string]: boolean} = {};
const svgUrl = this.getSvgUrl(); const loadCallbacks: {[url: string]: {(loadedSvgContent: string): void}[]} = [] as any;
if (!svgUrl) { const svgContents: {[url: string]: string} = {};
// we don't have good data
return <div class="icon-inner">{/* invalid svg */}</div>;
}
const svgContent = IonIcon.svgContents[svgUrl];
if (svgContent === this.svgContent) {
// we've already loaded up this svg at one point
// and the svg content we've loaded and assigned checks out
// render this svg!!
return <div class="icon-inner" innerHTML={svgContent}></div>;
}
// haven't loaded this svg yet
// start the request
Icon.loadSvgContent(svgUrl, loadedSvgContent => {
// we're finished loading the svg content!
// set to this.svgContent so we do another render
this.svgContent = loadedSvgContent;
});
// actively requesting the svg, so let's just render a div for now
return <div class="icon-inner">{/* loading svg */}</div>;
}
}
const IonIcon: GlobalIonIcon = {
activeRequests: {},
loadCallbacks: [] as any,
svgContents: {}
};
interface GlobalIonIcon {
activeRequests: {[url: string]: boolean};
loadCallbacks: {[url: string]: {(loadedSvgContent: string): void}[]};
svgContents: {[url: string]: string};
}

View File

@ -47,15 +47,6 @@ $item-ios-detail-push-color: $list-ios-border-color !default;
/// @prop - Icon for the detail arrow /// @prop - Icon for the detail arrow
$item-ios-detail-push-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 20'><path d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z' fill='#{$item-ios-detail-push-color}'/></svg>" !default; $item-ios-detail-push-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 20'><path d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z' fill='#{$item-ios-detail-push-color}'/></svg>" !default;
/// @prop - Background for the divider
$item-ios-divider-background: #f7f7f7 !default;
/// @prop - Color for the divider
$item-ios-divider-color: #222 !default;
/// @prop - Padding for the divider
$item-ios-divider-padding: 5px 15px !default;
// iOS Item // iOS Item
// -------------------------------------------------- // --------------------------------------------------

View File

@ -35,21 +35,6 @@ $item-md-detail-push-color: $list-md-border-color !default;
/// @prop - Icon for the detail arrow /// @prop - Icon for the detail arrow
$item-md-detail-push-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 20'><path d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z' fill='#{$item-md-detail-push-color}'/></svg>" !default; $item-md-detail-push-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 20'><path d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z' fill='#{$item-md-detail-push-color}'/></svg>" !default;
/// @prop - Color for the divider
$item-md-divider-color: #858585 !default;
/// @prop - Background for the divider
$item-md-divider-background: #fff !default;
/// @prop - Font size for the divider
$item-md-divider-font-size: $item-md-body-text-font-size !default;
/// @prop - Border bottom for the divider
$item-md-divider-border-bottom: 1px solid $list-md-border-color !default;
/// @prop - Padding for the divider
$item-md-divider-padding: 5px 15px !default;
.item-md { .item-md {
@include padding-horizontal($item-md-padding-start, 0); @include padding-horizontal($item-md-padding-start, 0);

View File

@ -86,3 +86,14 @@ ion-input.item {
align-items: flex-start; align-items: flex-start;
} }
.item-cover {
@include position(0, null, null, 0);
position: absolute;
width: 100%;
height: 100%;
background: transparent;
cursor: pointer;
}

View File

@ -41,21 +41,6 @@ $item-wp-detail-push-color: $input-wp-border-color !default;
/// @prop - Icon for the detail arrow /// @prop - Icon for the detail arrow
$item-wp-detail-push-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 20'><path d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z' fill='#{$item-wp-detail-push-color}'/></svg>" !default; $item-wp-detail-push-svg: "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 20'><path d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z' fill='#{$item-wp-detail-push-color}'/></svg>" !default;
/// @prop - Color for the divider
$item-wp-divider-color: $list-wp-text-color !default;
/// @prop - Background for the divider
$item-wp-divider-background: #fff !default;
/// @prop - Bodrer bottom for the divider
$item-wp-divider-border-bottom: 1px solid $list-wp-border-color !default;
/// @prop - Font size for the divider
$item-wp-divider-font-size: 2rem !default;
/// @prop - Padding for the divider
$item-wp-divider-padding: 5px 15px !default;
.item-wp { .item-wp {
@include padding-horizontal($item-wp-padding-start, 0); @include padding-horizontal($item-wp-padding-start, 0);

View File

@ -5,10 +5,8 @@
// iOS List Header // iOS List Header
// -------------------------------------------------- // --------------------------------------------------
// deprecated
$list-ios-header-padding-left: $item-ios-padding-start !default;
/// @prop - Padding start of the header in a list /// @prop - Padding start of the header in a list
$list-ios-header-padding-start: $list-ios-header-padding-left !default; $list-ios-header-padding-start: $item-ios-padding-start !default;
/// @prop - Border bottom of the header in a list /// @prop - Border bottom of the header in a list
$list-ios-header-border-bottom: $hairlines-width solid $list-ios-border-color !default; $list-ios-header-border-bottom: $hairlines-width solid $list-ios-border-color !default;

View File

@ -1,4 +1,4 @@
@import "../../themes/ionic.globals.ios"; @import "../../themes/ionic.globals.md";
@import "./list-header"; @import "./list-header";
// Material Design List Header // Material Design List Header
@ -7,10 +7,8 @@
/// @prop - Margin bottom of the header in a list /// @prop - Margin bottom of the header in a list
$list-md-header-margin-bottom: 13px !default; $list-md-header-margin-bottom: 13px !default;
// deprecated
$list-md-header-padding-left: $item-md-padding-start !default;
/// @prop - Padding start of the header in a list /// @prop - Padding start of the header in a list
$list-md-header-padding-start: $list-md-header-padding-left !default; $list-md-header-padding-start: $item-md-padding-start !default;
/// @prop - Minimum height of the header in a list /// @prop - Minimum height of the header in a list
$list-md-header-min-height: 4.5rem !default; $list-md-header-min-height: 4.5rem !default;

View File

@ -3,6 +3,11 @@ import { Component } from '@stencil/core';
@Component({ @Component({
tag: 'ion-list-header', tag: 'ion-list-header',
styleUrls: {
ios: 'list-header.ios.scss',
md: 'list-header.md.scss',
wp: 'list-header.wp.scss'
},
host: { host: {
theme: 'list-header' theme: 'list-header'
} }

View File

@ -4,10 +4,8 @@
// Windows List Header // Windows List Header
// -------------------------------------------------- // --------------------------------------------------
// deprecated
$list-wp-header-padding-left: $item-wp-padding-start !default;
/// @prop - Padding start of the header in a list /// @prop - Padding start of the header in a list
$list-wp-header-padding-start: $list-wp-header-padding-left !default; $list-wp-header-padding-start: $item-wp-padding-start !default;
/// @prop - Border bottom of the header in a list /// @prop - Border bottom of the header in a list
$list-wp-header-border-bottom: 1px solid $list-wp-border-color !default; $list-wp-header-border-bottom: 1px solid $list-wp-border-color !default;

View File

@ -1,7 +1,7 @@
import { Component, Event, EventEmitter, Prop, State } from '@stencil/core'; import { Component, Element, Event, EventEmitter, Prop, State } from '@stencil/core';
import { CssClassMap } from '../../index'; import { CssClassMap } from '../../index';
import { createThemedClasses } from '../../utils/theme'; import { createThemedClasses, getElementClassObject } from '../../utils/theme';
/** /**
@ -49,6 +49,8 @@ export class SegmentButton {
mode: string; mode: string;
color: string; color: string;
@Element() el: HTMLElement;
@Event() ionClick: EventEmitter; @Event() ionClick: EventEmitter;
@State() activated: boolean = false; @State() activated: boolean = false;
@ -92,7 +94,7 @@ export class SegmentButton {
/** /**
* @hidden * @hidden
* Get the element classes to add to the child element * Get the classes for the segment button state
*/ */
getElementClassList() { getElementClassList() {
let classList = [].concat( let classList = [].concat(
@ -104,9 +106,10 @@ export class SegmentButton {
} }
render() { render() {
const segmentButtonCss = createThemedClasses(this.mode, this.color, 'segment-button'); const themedClasses = createThemedClasses(this.mode, this.color, 'segment-button');
const hostClasses = getElementClassObject(this.el.classList);
var segmentButtonClasses: CssClassMap = [] const elementClasses: CssClassMap = []
.concat( .concat(
this.getElementClassList() this.getElementClassList()
) )
@ -115,10 +118,14 @@ export class SegmentButton {
return prevValue; return prevValue;
}, {}); }, {});
segmentButtonClasses = Object.assign(segmentButtonClasses, segmentButtonCss); const buttonClasses = {
...themedClasses,
...hostClasses,
...elementClasses
};
return [ return [
<button onClick={this.segmentButtonClick.bind(this)} class={segmentButtonClasses} aria-pressed={this.activated}> <button onClick={this.segmentButtonClick.bind(this)} class={buttonClasses} aria-pressed={this.activated}>
<slot></slot> <slot></slot>
</button> </button>
]; ];

View File

@ -0,0 +1,16 @@
import { Component } from '@stencil/core';
@Component({
tag: 'ion-option',
host: {
theme: 'option'
}
})
export class option {
render() {
return <div class="my-option"></div>;
}
}

View File

@ -0,0 +1,56 @@
@import "../../themes/ionic.globals.ios";
@import "./select";
// iOS Select
// --------------------------------------------------
/// @prop - Padding top of the select
$select-ios-padding-top: $item-ios-padding-top !default;
/// @prop - Padding end of the select
$select-ios-padding-end: ($item-ios-padding-end / 2) !default;
/// @prop - Padding bottom of the select
$select-ios-padding-bottom: $item-ios-padding-bottom !default;
/// @prop - Padding start of the select
$select-ios-padding-start: $item-ios-padding-start !default;
/// @prop - Color of the select icon
$select-ios-icon-color: #999 !default;
/// @prop - Color of the select placeholder
$select-ios-placeholder-color: $select-ios-icon-color !default;
.select-ios {
@include padding($select-ios-padding-top, $select-ios-padding-end, $select-ios-padding-bottom, $select-ios-padding-start);
}
.select-ios .select-placeholder {
color: $select-ios-placeholder-color;
}
.select-ios .select-icon {
position: relative;
width: 12px;
height: 18px;
}
.select-ios .select-icon .select-icon-inner {
@include position(50%, null, null, 5px);
@include margin(-2px, null, null, null);
position: absolute;
width: 0;
height: 0;
border-top: 5px solid;
border-right: 5px solid transparent;
border-left: 5px solid transparent;
color: $select-ios-icon-color;
pointer-events: none;
}

View File

@ -0,0 +1,60 @@
@import "../../themes/ionic.globals.md";
@import "./select";
// Material Design Select
// --------------------------------------------------
/// @prop - Padding top of the select
$select-md-padding-top: $item-md-padding-top !default;
/// @prop - Padding end of the select
$select-md-padding-end: ($item-md-padding-end / 2) !default;
/// @prop - Padding bottom of the select
$select-md-padding-bottom: $item-md-padding-bottom !default;
/// @prop - Padding start of the select
$select-md-padding-start: $item-md-padding-start !default;
/// @prop - Color of the select icon
$select-md-icon-color: #999 !default;
/// @prop - Color of the select placeholder
$select-md-placeholder-color: $select-md-icon-color !default;
.select-md {
@include padding($select-md-padding-top, $select-md-padding-end, $select-md-padding-bottom, $select-md-padding-start);
}
.select-md .select-placeholder {
color: $select-md-placeholder-color;
}
.select-md .item-select ion-label {
@include margin-horizontal(0, null);
}
.select-md .select-icon {
position: relative;
width: 12px;
height: 19px;
}
.select-md .select-icon .select-icon-inner {
@include position(50%, null, null, 5px);
@include margin(-3px, null, null, null);
position: absolute;
width: 0;
height: 0;
border-top: 5px solid;
border-right: 5px solid transparent;
border-left: 5px solid transparent;
color: $select-md-icon-color;
pointer-events: none;
}

View File

@ -0,0 +1,56 @@
@import "../../themes/ionic.globals";
// Select
// --------------------------------------------------
/// @prop - Margin top of the select popover list
$select-popover-list-margin-top: -1px !default;
/// @prop - Margin end of the select popover list
$select-popover-list-margin-end: 0 !default;
/// @prop - Margin bottom of the select popover list
$select-popover-list-margin-bottom: -1px !default;
/// @prop - Margin start of the select popover list
$select-popover-list-margin-start: 0 !default;
ion-select {
display: flex;
overflow: hidden;
max-width: 45%;
}
.select-text {
overflow: hidden;
flex: 1;
min-width: 16px;
font-size: inherit;
text-overflow: ellipsis;
white-space: nowrap;
}
.item-multiple-inputs ion-select {
position: relative;
}
.select-disabled,
.item-select-disabled ion-label {
opacity: .4;
pointer-events: none;
}
.select-popover ion-list {
@include margin($select-popover-list-margin-top, $select-popover-list-margin-end, $select-popover-list-margin-bottom, $select-popover-list-margin-start);
}
// TODO remove
.select .option {
display: none;
}

View File

@ -0,0 +1,365 @@
import { Component, CssClassMap, Event, EventEmitter, Prop } from '@stencil/core';
@Component({
tag: 'ion-select',
styleUrls: {
ios: 'select.ios.scss',
md: 'select.md.scss',
wp: 'select.wp.scss'
},
host: {
theme: 'select'
}
})
export class Select {
text: any;
id: any;
labelId: any;
/**
* @input {boolean} If true, the user cannot interact with this element. Defaults to `false`.
*/
@Prop() disabled: boolean = false;
/**
* @input {string} The text to display on the cancel button. Default: `Cancel`.
*/
@Prop() cancelText: string = 'Cancel';
/**
* @input {string} The text to display on the ok button. Default: `OK`.
*/
@Prop() okText: string = 'OK';
/**
* @input {string} The text to display when the select is empty.
*/
@Prop() placeholder: string;
/**
* @input {any} Any additional options that the `alert` or `action-sheet` interface can take.
* See the [AlertController API docs](../../alert/AlertController/#create) and the
* [ActionSheetController API docs](../../action-sheet/ActionSheetController/#create) for the
* create options for each interface.
*/
@Prop() selectOptions: any = {};
/**
* @input {string} The interface the select should use: `action-sheet`, `popover` or `alert`. Default: `alert`.
*/
@Prop() interface: string = '';
/**
* @input {string} The text to display instead of the selected option's value.
*/
@Prop() selectedText: string;
/**
* @input {boolean} If true, the element can accept multiple values.
*/
@Prop() multiple: boolean;
/**
* @output {EventEmitter} Emitted when the selection is cancelled.
*/
@Event() ionCancel: EventEmitter;
hostData() {
return {
class: {
'select-disabled': this.disabled
}
};
}
render() {
let addPlaceholderClass = false
let selectText = this.selectedText || this.text;
if (!selectText && this.placeholder) {
selectText = this.placeholder;
addPlaceholderClass = true;
}
const selectTextClasses: CssClassMap = {
'select-text': true,
'select-placeholder': addPlaceholderClass
};
return [
// add placeholder class
<div class={selectTextClasses}>{ selectText }</div>,
<div class="select-icon">
<div class="select-icon-inner"></div>
</div>,
<button
aria-haspopup="true"
id={this.id}
aria-labelledby={this.labelId}
aria-disabled={this.disabled ? "true" : false}
class="item-cover">
</button>
];
}
}
// export class Select extends BaseInput<any> implements OnDestroy {
// _options: QueryList<Option>;
// _overlay: ActionSheet | Alert | Popover;
// _texts: string[] = [];
// _text: string = '';
// @HostListener('click', ['$event'])
// _click(ev: UIEvent) {
// if (ev.detail === 0) {
// // do not continue if the click event came from a form submit
// return;
// }
// ev.preventDefault();
// ev.stopPropagation();
// this.open(ev);
// }
// @HostListener('keyup.space')
// _keyup() {
// this.open();
// }
// /**
// * @hidden
// */
// getValues(): any[] {
// const values = Array.isArray(this._value) ? this._value : [this._value];
// assert(this._multi || values.length <= 1, 'single only can have one value');
// return values;
// }
// /**
// * Open the select interface.
// */
// open(ev?: UIEvent) {
// if (this.isFocus() || this._disabled) {
// return;
// }
// console.debug('select, open alert');
// // the user may have assigned some options specifically for the alert
// const selectOptions = deepCopy(this.selectOptions);
// // make sure their buttons array is removed from the options
// // and we create a new array for the alert's two buttons
// selectOptions.buttons = [{
// text: this.cancelText,
// role: 'cancel',
// handler: () => {
// this.ionCancel.emit(this);
// }
// }];
// // if the selectOptions didn't provide a title then use the label's text
// if (!selectOptions.title && this._item) {
// selectOptions.title = this._item.getLabelText();
// }
// let options = this._options.toArray();
// if (this.interface === 'action-sheet' && options.length > 6) {
// console.warn('Interface cannot be "action-sheet" with more than 6 options. Using the "alert" interface.');
// this.interface = 'alert';
// }
// if ((this.interface === 'action-sheet' || this.interface === 'popover') && this._multi) {
// console.warn('Interface cannot be "' + this.interface + '" with a multi-value select. Using the "alert" interface.');
// this.interface = 'alert';
// }
// if (this.interface === 'popover' && !ev) {
// console.warn('Interface cannot be "popover" without UIEvent.');
// this.interface = 'alert';
// }
// let overlay: ActionSheet | Alert | Popover;
// if (this.interface === 'action-sheet') {
// selectOptions.buttons = selectOptions.buttons.concat(options.map(input => {
// return {
// role: (input.selected ? 'selected' : ''),
// text: input.text,
// handler: () => {
// this.value = input.value;
// input.ionSelect.emit(input.value);
// }
// };
// }));
// var selectCssClass = 'select-action-sheet';
// // If the user passed a cssClass for the select, add it
// selectCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
// selectOptions.cssClass = selectCssClass;
// overlay = new ActionSheet(this._app, selectOptions, this.config);
// } else if (this.interface === 'popover') {
// let popoverOptions: SelectPopoverOption[] = options.map(input => ({
// text: input.text,
// checked: input.selected,
// disabled: input.disabled,
// value: input.value,
// handler: () => {
// this.value = input.value;
// input.ionSelect.emit(input.value);
// }
// }));
// var popoverCssClass = 'select-popover';
// // If the user passed a cssClass for the select, add it
// popoverCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
// overlay = new Popover(this._app, SelectPopover, {
// options: popoverOptions
// }, {
// cssClass: popoverCssClass
// }, this.config, this.deepLinker);
// // ev.target is readonly.
// // place popover regarding to ion-select instead of .button-inner
// Object.defineProperty(ev, 'target', { value: ev.currentTarget });
// selectOptions.ev = ev;
// } else {
// // default to use the alert interface
// this.interface = 'alert';
// // user cannot provide inputs from selectOptions
// // alert inputs must be created by ionic from ion-options
// selectOptions.inputs = this._options.map(input => {
// return {
// type: (this._multi ? 'checkbox' : 'radio'),
// label: input.text,
// value: input.value,
// checked: input.selected,
// disabled: input.disabled,
// handler: (selectedOption: any) => {
// // Only emit the select event if it is being checked
// // For multi selects this won't emit when unchecking
// if (selectedOption.checked) {
// input.ionSelect.emit(input.value);
// }
// }
// };
// });
// var selectCssClass = 'select-alert';
// // create the alert instance from our built up selectOptions
// overlay = new Alert(this._app, selectOptions, this.config);
// if (this._multi) {
// // use checkboxes
// selectCssClass += ' multiple-select-alert';
// } else {
// // use radio buttons
// selectCssClass += ' single-select-alert';
// }
// // If the user passed a cssClass for the select, add it
// selectCssClass += selectOptions.cssClass ? ' ' + selectOptions.cssClass : '';
// overlay.setCssClass(selectCssClass);
// overlay.addButton({
// text: this.okText,
// handler: (selectedValues) => this.value = selectedValues
// });
// }
// overlay.present(selectOptions);
// this._fireFocus();
// overlay.onDidDismiss(() => {
// this._fireBlur();
// this._overlay = undefined;
// });
// this._overlay = overlay;
// }
// /**
// * Close the select interface.
// */
// close(): Promise<any> {
// if (!this._overlay || !this.isFocus()) {
// return;
// }
// return this._overlay.dismiss();
// }
// /**
// * @hidden
// */
// get text() {
// return (this._multi ? this._texts : this._texts.join());
// }
// /**
// * @private
// */
// @ContentChildren(Option)
// set options(val: QueryList<Option>) {
// this._options = val;
// const values = this.getValues();
// if (values.length === 0) {
// // there are no values set at this point
// // so check to see who should be selected
// // we use writeValue() because we don't want to update ngModel
// this.writeValue(val.filter(o => o.selected).map(o => o.value));
// } else {
// this._inputUpdated();
// }
// }
// _inputShouldChange(val: string[]|string): boolean {
// return !deepEqual(this._value, val);
// }
// /**
// * TODO: REMOVE THIS
// * @hidden
// */
// _inputChangeEvent(): any {
// return this.value;
// }
// /**
// * @hidden
// */
// _inputUpdated() {
// this._texts.length = 0;
// if (this._options) {
// this._options.forEach(option => {
// // check this option if the option's value is in the values array
// option.selected = this.getValues().some(selectValue => {
// return isCheckedProperty(selectValue, option.value);
// });
// if (option.selected) {
// this._texts.push(option.text);
// }
// });
// }
// this._text = this._texts.join(', ');
// }
// }

View File

@ -0,0 +1,93 @@
@import "../../themes/ionic.globals.wp";
@import "./select";
// Windows Select
// --------------------------------------------------
/// @prop - Padding top and bottom of the select
$select-wp-padding-vertical: 0 !default;
/// @prop - Padding start/end of the select
$select-wp-padding-horizontal: ($item-wp-padding-end / 2) !default;
/// @prop - Margin top of the select
$select-wp-margin-top: $item-wp-padding-top !default;
/// @prop - Margin end of the select
$select-wp-margin-end: ($item-wp-padding-end / 2) !default;
/// @prop - Margin bottom of the select
$select-wp-margin-bottom: $item-wp-padding-bottom !default;
/// @prop - Margin start of the select
$select-wp-margin-start: ($item-wp-padding-start / 2) !default;
/// @prop - Border width of the select
$select-wp-border-width: 2px !default;
/// @prop - Border color of the select
$select-wp-border-color: $input-wp-border-color !default;
/// @prop - Width of the select icon
$select-wp-icon-width: 18px !default;
/// @prop - Width of the select icon arrow
$select-wp-icon-arrow-width: 2px !default;
/// @prop - Color of the select icon
$select-wp-icon-color: $select-wp-border-color !default;
/// @prop - Color of the select placeholder
$select-wp-placeholder-color: $select-wp-icon-color !default;
.select-wp {
@include margin($select-wp-margin-top, $select-wp-margin-end, $select-wp-margin-bottom, $select-wp-margin-start);
@include padding($select-wp-padding-vertical, $select-wp-padding-horizontal);
flex: 1;
max-width: 100%;
border: $select-wp-border-width solid $select-wp-border-color;
line-height: 3rem;
}
.select-wp .select-placeholder {
color: $select-wp-placeholder-color;
}
.item-wp.item-select ion-label {
@include margin-horizontal(0, null);
}
.select-wp .select-icon {
position: relative;
align-self: center;
width: $select-wp-icon-width;
height: $select-wp-icon-width;
}
.select-wp .select-icon .select-icon-inner {
@include position(3px, null, null, 5px);
position: absolute;
display: block;
width: ($select-wp-icon-width / 2);
height: ($select-wp-icon-width / 2);
border-top: $select-wp-icon-arrow-width solid $select-wp-icon-color;
border-right: $select-wp-icon-arrow-width solid $select-wp-icon-color;
transform: rotate(135deg);
pointer-events: none;
}
.select-wp .select-text {
min-height: 3rem;
}

View File

@ -0,0 +1,237 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Ionic Select</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
</head>
<body>
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Select</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="outer-content test-content">
<ion-list>
<ion-list-header>Single Value Select</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
<ion-select name="gender" placeholder="Select One">
<ion-option value="f">Female</ion-option>
<ion-option value="m">Male</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Hair Color</ion-label>
<ion-select name="hairColor" ok-text="Okay" cancel-text="Dismiss">
<ion-option value="brown">Brown</ion-option>
<ion-option value="blonde">Blonde</ion-option>
<ion-option value="black">Black</ion-option>
<ion-option value="red">Red</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Gaming</ion-label>
<ion-select name="gaming" ok-text="Okay" cancel-text="Dismiss">
<ion-option value="nes">NES</ion-option>
<ion-option value="n64">Nintendo64</ion-option>
<ion-option value="ps">PlayStation</ion-option>
<ion-option value="genesis">Sega Genesis</ion-option>
<ion-option value="saturn">Sega Saturn</ion-option>
<ion-option value="snes">SNES</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Date</ion-label>
<ion-select (ionChange)="monthChange($event)" placeholder="Month">
<ion-option value="01">January</ion-option>
<ion-option value="02">February</ion-option>
<ion-option value="03" selected="true">March</ion-option>
<ion-option value="04">April</ion-option>
<ion-option value="05">May</ion-option>
<ion-option value="06">June</ion-option>
<ion-option value="07">July</ion-option>
<ion-option value="08">August</ion-option>
<ion-option value="09">September</ion-option>
<ion-option value="10">October</ion-option>
<ion-option value="11">November</ion-option>
<ion-option value="12">December</ion-option>
</ion-select>
<ion-select (ionChange)="yearChange($event)" placeholder="Year">
<ion-option>1989</ion-option>
<ion-option>1990</ion-option>
<ion-option>1991</ion-option>
<ion-option>1992</ion-option>
<ion-option>1993</ion-option>
<ion-option selected="true">1994</ion-option>
<ion-option>1995</ion-option>
<ion-option>1996</ion-option>
<ion-option>1997</ion-option>
<ion-option>1998</ion-option>
<ion-option>1999</ion-option>
</ion-select>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>Popover Interface Select</ion-list-header>
<ion-item>
<ion-label>Gender</ion-label>
<ion-select name="gender" interface="popover">
<ion-option value="f">Female</ion-option>
<ion-option value="m">Male</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Gaming</ion-label>
<ion-select name="gaming" ok-text="Okay" cancel-text="Dismiss" selected-text="Nintendo 64" interface="popover">
<ion-option value="nes">NES</ion-option>
<ion-option value="n64">Nintendo64</ion-option>
<ion-option value="ps">PlayStation</ion-option>
<ion-option value="genesis">Sega Genesis</ion-option>
<ion-option value="saturn">Sega Saturn</ion-option>
<ion-option value="snes">SNES</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Date</ion-label>
<ion-select (ionChange)="monthChange($event)" placeholder="Month" interface="popover">
<ion-option value="01">January</ion-option>
<ion-option value="02">February</ion-option>
<ion-option value="03" selected="true">March</ion-option>
<ion-option value="04">April</ion-option>
<ion-option value="05">May</ion-option>
<ion-option value="06">June</ion-option>
<ion-option value="07">July</ion-option>
<ion-option value="08">August</ion-option>
<ion-option value="09">September</ion-option>
<ion-option value="10">October</ion-option>
<ion-option value="11">November</ion-option>
<ion-option value="12">December</ion-option>
</ion-select>
<ion-select (ionChange)="yearChange($event)" placeholder="Year" interface="popover">
<ion-option>1989</ion-option>
<ion-option>1990</ion-option>
<ion-option>1991</ion-option>
<ion-option>1992</ion-option>
<ion-option>1993</ion-option>
<ion-option selected="true">1994</ion-option>
<ion-option>1995</ion-option>
<ion-option>1996</ion-option>
<ion-option>1997</ion-option>
<ion-option>1998</ion-option>
<ion-option>1999</ion-option>
</ion-select>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>Multiple Value Select</ion-list-header>
<ion-item>
<ion-label>Toppings</ion-label>
<ion-select name="toppings" multiple="true" cancel-text="Nah" ok-text="Okay!">
<ion-option value="bacon">Bacon</ion-option>
<ion-option value="olives">Black Olives</ion-option>
<ion-option value="xcheese">Extra Cheese</ion-option>
<ion-option value="peppers">Green Peppers</ion-option>
<ion-option value="mushrooms">Mushrooms</ion-option>
<ion-option value="onions">Onions</ion-option>
<ion-option value="pepperoni">Pepperoni</ion-option>
<ion-option value="pineapple">Pineapple</ion-option>
<ion-option value="sausage">Sausage</ion-option>
<ion-option value="Spinach">Spinach</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Pets</ion-label>
<ion-select name="pets" multiple="true">
<ion-option value="bird">Bird</ion-option>
<ion-option value="cat">Cat</ion-option>
<ion-option value="dog">Dog</ion-option>
<ion-option value="honeybadger">Honey Badger</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Skittles</ion-label>
<ion-select name="skittles" multiple="true" ok-text="Okay" cancel-text="Dismiss">
<ion-option value="red">Red</ion-option>
<ion-option value="purple">Purple</ion-option>
<ion-option value="yellow">Yellow</ion-option>
<ion-option value="orange">Orange</ion-option>
<ion-option value="green">Green</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Disabled</ion-label>
<ion-select multiple disabled="true">
<ion-option checked="true">Selected Text</ion-option>
</ion-select>
</ion-item>
</ion-list>
<ion-list>
<ion-list-header>Action Sheet Interface Select</ion-list-header>
<ion-item>
<ion-label>Mute Notifications</ion-label>
<ion-select name="notifications" interface="action-sheet">
<ion-option value="mute_15">For 15 Minutes</ion-option>
<ion-option value="mute_1">For 1 Hour</ion-option>
<ion-option value="mute_23">For 24 Hours</ion-option>
<ion-option value="mute_inf">Until I turn it back on</ion-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Rating</ion-label>
<ion-select name="rating" interface="action-sheet">
<ion-option value="1">1 Star</ion-option>
<ion-option value="2">2 Stars</ion-option>
<ion-option value="3">3 Stars</ion-option>
<ion-option value="4">4 Stars</ion-option>
<ion-option value="5">5 Stars</ion-option>
</ion-select>
</ion-item>
</ion-list>
<div text-center>
<ion-button onclick="toggleBoolean('dynamicDisabled', 'disabled')">
Toggle Disabled
</ion-button>
</div>
</ion-content>
<script>
function toggleBoolean(id, prop) {
var ele = document.getElementById(id);
var isTrue = ele[prop] ? false : true;
ele[prop] = isTrue;
console.log('in toggleBoolean, setting', prop, 'to', isTrue);
}
</script>
</ion-app>
</body>
</html>

View File

@ -37,11 +37,11 @@ export class Spinner {
} }
hostData() { hostData() {
const spinnerThemedClasses = createThemedClasses(this.mode, this.color, `spinner spinner-${this.name}`); const themedClasses = createThemedClasses(this.mode, this.color, `spinner spinner-${this.name}`);
spinnerThemedClasses['spinner-paused'] = true; themedClasses['spinner-paused'] = true;
return { return {
class: spinnerThemedClasses class: themedClasses
}; };
} }

View File

@ -7,6 +7,6 @@
<script src="/dist/ionic.js"></script> <script src="/dist/ionic.js"></script>
</head> </head>
<body> <body>
<ion-spinner></ion-spinner> <ion-spinner name="bubbles"></ion-spinner>
</body> </body>
</html> </html>

View File

@ -53,10 +53,10 @@ export class ToolbarTitle {
color: string; color: string;
render() { render() {
const titleClasses = createThemedClasses(this.mode, this.color, 'toolbar-title'); const themedClasses = createThemedClasses(this.mode, this.color, 'toolbar-title');
return [ return [
<div class={titleClasses}> <div class={themedClasses}>
<slot></slot> <slot></slot>
</div> </div>
]; ];

View File

@ -1,4 +1,3 @@
export function isDef(v: any): boolean { return v !== undefined && v !== null; } export function isDef(v: any): boolean { return v !== undefined && v !== null; }
export function isUndef(v: any): boolean { return v === undefined || v === null; } export function isUndef(v: any): boolean { return v === undefined || v === null; }

View File

@ -1,10 +1,12 @@
import { CssClassMap } from '@stencil/core'; import { CssClassMap } from '@stencil/core';
/**
* Create the mode and color classes for the component based on the classes passed in
*/
export function createThemedClasses(mode: string, color: string, classes: string): CssClassMap {
let classObj: CssClassMap = {};
export function createThemedClasses(mode: string, color: string, classList: string): CssClassMap { return classes.split(' ')
let allClassObj: CssClassMap = {};
return classList.split(' ')
.reduce((classObj: CssClassMap, classString: string): CssClassMap => { .reduce((classObj: CssClassMap, classString: string): CssClassMap => {
classObj[classString] = true; classObj[classString] = true;
@ -18,5 +20,18 @@ export function createThemedClasses(mode: string, color: string, classList: stri
} }
return classObj; return classObj;
}, allClassObj); }, classObj);
}
/**
* Get the classes from a class list and return them as an object
*/
export function getElementClassObject(classList: DOMTokenList): CssClassMap {
let classObj: CssClassMap = {};
for (var i = 0; i < classList.length; i++) {
classObj[classList.item(i)] = true;
}
return classObj;
} }