feature(show-when): initial implementation of show-when

This commit is contained in:
Dan Bucholtz
2018-02-19 21:59:25 -06:00
parent 1794cd4b37
commit eb8591c268
5 changed files with 309 additions and 0 deletions

View File

@ -0,0 +1,65 @@
# ion-show-when
<!-- Auto Generated Below -->
## Properties
#### mediaQuery
string
#### mode
string
#### or
boolean
#### platform
string
#### size
string
## Attributes
#### media-query
string
#### mode
string
#### or
boolean
#### platform
string
#### size
string
----------------------------------------------
*Built with [StencilJS](https://stenciljs.com/)*

View File

@ -0,0 +1,7 @@
ion-show-when.show-content {
display: block;
}
ion-show-when.hide-content {
display: none !important;
}

View File

@ -0,0 +1,46 @@
import { Component, Element, Prop } from '@stencil/core';
import { Config, PlatformConfig } from '../../index';
import {
DisplayWhen,
componentWillLoadImpl,
} from '../../utils/show-hide-when-utils';
@Component({
tag: 'ion-show-when',
styleUrl: './show-when.scss'
})
export class ShowWhen implements DisplayWhen {
@Element() element: HTMLElement;
@Prop({ context: 'config' }) config: Config;
@Prop({ context: 'platforms' }) calculatedPlatforms: PlatformConfig[];
@Prop() mediaQuery: string = null;
@Prop() size: string = null;
@Prop() mode: string = null;
@Prop() platform: string = null;
@Prop() or = false;
passesTest = false;
componentWillLoad() {
return componentWillLoadImpl(this);
}
hostData() {
return {
class: {
'show-content': this.passesTest,
'hide-content': !this.passesTest
}
};
}
render() {
return <slot></slot>
}
}

View File

@ -0,0 +1,96 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Show When - Basic</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<script src="/dist/ionic.js"></script>
</head>
<body>
<ion-app>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Show when - Basic</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<h2>Mode Tests</h2>
<ion-show-when mode="md, ios">
<div>Shows on MD, iOS</div>
</ion-show-when>
<ion-show-when mode="md">
<div>Shows on MD only</div>
</ion-show-when>
<ion-show-when mode="ios">
<div>Shows on iOS only</div>
</ion-show-when>
<h2>Platform Tests</h2>
<ion-show-when platform="android,ios">
<div>Render on Android and iOS</div>
</ion-show-when>
<ion-show-when platform="ios">
<div>Only render on iOS</div>
</ion-show-when>
<ion-show-when platform="android">
<div>Only render on Android</div>
</ion-show-when>
<ion-show-when platform="ipad">
<div>Only render on ipad</div>
</ion-show-when>
<ion-show-when platform="phablet">
<div>Only render on phablet</div>
</ion-show-when>
<ion-show-when platform="iphone">
<div>Only render on phone</div>
</ion-show-when>
<h2>Size Tests</h2>
<ion-show-when size="xs">
<div>Only render on xs</div>
</ion-show-when>
<ion-show-when size="sm">
<div>Only render on sm</div>
</ion-show-when>
<ion-show-when size="md">
<div>Only render on md</div>
</ion-show-when>
<ion-show-when size="lg">
<div>Only render on lg</div>
</ion-show-when>
<ion-show-when size="xl">
<div>Only render on xl</div>
</ion-show-when>
<ion-show-when size="xs, m">
<div>Only render on XS or m</div>
</ion-show-when>
</ion-content>
</ion-page>
</ion-app>
<script>
</script>
</body>
</html>

View File

@ -0,0 +1,95 @@
import { Config, PlatformConfig } from '../index';
export function componentWillLoadImpl(displayWhen: DisplayWhen) {
displayWhen.passesTest = getTestResult(displayWhen);
}
export function isPlatformMatch(platforms: string[], multiPlatformString: string) {
const userProvidedPlatforms = multiPlatformString.replace(/\s/g, '').split(',');
for (const userProvidedPlatform of userProvidedPlatforms) {
for (const platform of platforms) {
if (userProvidedPlatform === platform) {
return true;
}
}
}
return false;
}
export function isModeMatch(config: Config, multiModeString: string) {
// you can only ever be in one mode, so if an entry from the list matches, return true
const modes = multiModeString.replace(/\s/g, '').split(',');
for (const mode of modes) {
if (config.get('mode') === mode) {
return true;
}
}
return false;
}
export function isMediaQueryMatch(mediaQuery: string) {
return window.matchMedia(mediaQuery).matches;
}
export function isSizeMatch(multiSizeString: string) {
const sizes = multiSizeString.replace(/\s/g, '').split(',');
const booleans = sizes.map(size => {
const mediaQuery = sizeToMediaQueryMap.get(size);
if (!mediaQuery) {
return false;
}
return window.matchMedia(mediaQuery).matches;
});
return booleans.reduce((prev, current) => prev || current);
}
export function getTestResult(displayWhen: DisplayWhen) {
const resultsToConsider: boolean[] = [];
if (displayWhen.mediaQuery) {
resultsToConsider.push(isMediaQueryMatch(displayWhen.mediaQuery));
}
if (displayWhen.size) {
resultsToConsider.push(isSizeMatch(displayWhen.size));
}
if (displayWhen.mode) {
resultsToConsider.push(isModeMatch(displayWhen.config, displayWhen.mode));
}
if (displayWhen.platform) {
const platformNames = displayWhen.calculatedPlatforms.map(platformConfig => platformConfig.name);
resultsToConsider.push(isPlatformMatch(platformNames, displayWhen.platform));
}
if (!resultsToConsider.length) {
return true;
}
if (resultsToConsider.length === 1) {
return resultsToConsider[0];
}
return resultsToConsider.reduce((prev: boolean, current: boolean) => {
if (displayWhen.or) {
return prev || current;
}
return prev && current;
});
}
const sizeToMediaQueryMap = new Map<string, string>();
sizeToMediaQueryMap.set('xs', '(min-width: 0px)');
sizeToMediaQueryMap.set('sm', '(min-width: 576px)');
sizeToMediaQueryMap.set('md', '(min-width: 768px)');
sizeToMediaQueryMap.set('lg', '(min-width: 992px)');
sizeToMediaQueryMap.set('xl', '(min-width: 1200px)');
export interface DisplayWhen {
calculatedPlatforms: PlatformConfig[];
config: Config;
mediaQuery: string;
mode: string;
or: boolean;
passesTest: boolean;
platform: string;
size: string;
}