refactor(item): remove no-lines attribute in favor of lines property (#14407)

* docs(components): update grammar and docs

* docs(item): update item documentation and add usage

* test(item): add lines test

* feat(list): add lines property to override borders on items

* feat(item): add lines property to override borders on items

* refactor(item): remove old uses of no-lines attribute

* fix(item-sliding): update item options to show border

- show the border on left options only if in a full list
- show the border on both options only if in an inset list (or ios by
default)
- don’t show border on either for no lines list (and md by default)

also renames isRightSide to isEndSide to match the side values

* chore(package): update package lock

* style(item): fix lint errors

* test(item): update item tests

* refactor(item): remove the custom styling of last child items

instead of us overriding first/last child items to have borders we are
going to add to the documentation how to style items with a full border

* fix(item): apply border to item inputs for MD mode

* docs(components): update docs based on new build

* docs(usage): update item usage to show lines being used

* fix(item): do not set the padding right to 0 on an item by default

* fix(item): cast lines to boolean

fixes: #5537 #13218 #12689 #12073 #9112
This commit is contained in:
Brandy Carney
2018-05-07 17:16:11 -04:00
committed by GitHub
parent 69cb2e2334
commit 427222cc29
43 changed files with 11821 additions and 171 deletions

View File

File diff suppressed because one or more lines are too long

11003
core/package-lock.json generated
View File

File diff suppressed because one or more lines are too long

View File

@@ -2721,7 +2721,7 @@ declare global {
namespace StencilComponents {
interface IonItemOptions {
'fireSwipeEvent': () => void;
'isRightSide': () => boolean;
'isEndSide': () => boolean;
/**
* The side the option button should be on. Possible values: `"start"` and `"end"`. Defaults to `"end"`. If you have multiple `ion-item-options`, a side must be provided for each.
*/
@@ -2837,6 +2837,10 @@ declare global {
* Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered.
*/
'href': string;
/**
* How the bottom border should be displayed on the item.
*/
'lines': 'full' | 'inset' | 'none';
/**
* The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`. For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
*/
@@ -2887,6 +2891,10 @@ declare global {
* Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered.
*/
'href'?: string;
/**
* How the bottom border should be displayed on the item.
*/
'lines'?: 'full' | 'inset' | 'none';
/**
* The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`. For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
*/
@@ -3019,6 +3027,10 @@ declare global {
* Get the [Item Sliding](../../item-sliding/ItemSliding) that is currently opene.
*/
'getOpenItem': () => HTMLIonItemSlidingElement | undefined;
/**
* How the bottom border should be displayed on all items.
*/
'lines': 'full' | 'inset' | 'none';
/**
* Set an [Item Sliding](../../item-sliding/ItemSliding) as the open item.
*/
@@ -3045,7 +3057,10 @@ declare global {
}
namespace JSXElements {
export interface IonListAttributes extends HTMLAttributes {
/**
* How the bottom border should be displayed on all items.
*/
'lines'?: 'full' | 'inset' | 'none';
}
}
}

View File

@@ -240,6 +240,7 @@ export class Datetime {
private emitStyle() {
this.ionStyle.emit({
'input': true,
'datetime': true,
'datetime-disabled': this.disabled,
'input-has-value': this.hasValue()

View File

@@ -10,11 +10,11 @@
background-color: $item-option-button-ios-background-color;
}
.list-ios .item-options-right ion-item-option:last-child {
.list-ios .item-options-end ion-item-option:last-child {
@include safe-area-padding-horizontal(null, .7em);
}
.list-ios .item-options-left ion-item-option:first-child {
.list-ios .item-options-start ion-item-option:first-child {
@include safe-area-padding-horizontal(.7em, null);
}

View File

@@ -21,13 +21,10 @@
}
}
ion-item-options .item-option-button-inner {
flex-direction: column;
}
.item-option-button-inner {
display: flex;
flex-direction: column;
flex-flow: row nowrap;
flex-shrink: 0;
align-items: center;
@@ -57,7 +54,7 @@ ion-item-options .item-option-button-inner {
transition-timing-function: cubic-bezier(.65, .05, .36, 1);
}
.item-sliding-active-swipe-right .item-options-right .item-option-expandable {
.item-sliding-active-swipe-right .item-options-end .item-option-expandable {
transition-duration: .6s;
transition-property: padding-left;
@@ -75,7 +72,7 @@ ion-item-options .item-option-button-inner {
}
}
.item-sliding-active-swipe-left .item-options-left .item-option-expandable {
.item-sliding-active-swipe-left .item-options-start .item-option-expandable {
transition-duration: .6s;
transition-property: padding-right;

View File

@@ -4,14 +4,33 @@
// iOS Item Options
// --------------------------------------------------
.list-ios ion-item-options {
border-bottom: $hairlines-width solid $item-ios-border-color;
.item-options-ios {
border-bottom-width: 0;
border-bottom-style: $item-ios-border-bottom-style;
border-bottom-color: $item-ios-border-bottom-color;
&.item-options-end {
border-bottom-width: $item-ios-border-bottom-width;
}
}
// iOS No Lines List
// --------------------------------------------------
.list-ios[no-lines] ion-item-options {
border-width: 0;
.list-ios-lines-none .item-options-ios {
border-bottom-width: 0;
}
// iOS Full/Inset Lines List
// --------------------------------------------------
// If the lines are full put a border on both item options
// If the lines are inset we should only show the border on the end
// because dragging open start options isn't continuous
.list-ios-lines-full .item-options-ios,
.list-ios-lines-inset .item-options-ios.item-options-end {
border-bottom-width: $item-ios-border-bottom-width;
}

View File

@@ -1,4 +1,6 @@
@import "../../themes/ionic.globals.ios";
@import "../item/item.ios.vars";
// iOS Item Options
// --------------------------------------------------

View File

@@ -4,14 +4,28 @@
// Material Design Item Options
// --------------------------------------------------
.list-md ion-item-options {
border-bottom: 1px solid $item-md-border-color;
.item-options-md {
border-bottom-width: 0;
border-bottom-style: $item-md-border-bottom-style;
border-bottom-color: $item-md-border-bottom-color;
}
// Material Design No Lines List
// --------------------------------------------------
.list-md[no-lines] ion-item-options {
border-width: 0;
.list-md-lines-none .item-options-md {
border-bottom-width: 0;
}
// Material Design Full/Inset Lines List
// --------------------------------------------------
// If the lines are full put a border on both item options
// If the lines are inset we should only show the border on the end
// because dragging open start options isn't continuous
.list-md-lines-full .item-options-md,
.list-md-lines-inset .item-options-md.item-options-end {
border-bottom-width: $item-md-border-bottom-width;
}

View File

@@ -1,4 +1,6 @@
@import "../../themes/ionic.globals.md";
@import "../item/item.md.vars";
// Material Design Item Options
// --------------------------------------------------

View File

@@ -26,7 +26,7 @@ ion-item-options {
@include rtl() {
justify-content: flex-start;
&:not(.item-options-right) {
&:not(.item-options-end) {
// scss-lint:disable PropertySpelling
right: auto;
left: 0;
@@ -40,7 +40,7 @@ ion-item-options {
}
}
.item-options-left {
.item-options-start {
@include multi-dir() {
// scss-lint:disable PropertySpelling
right: auto;
@@ -58,7 +58,7 @@ ion-item-options {
.item-sliding-active-slide {
@include rtl() {
&.item-sliding-active-options-left ion-item-options:not(.item-options-right) {
&.item-sliding-active-options-left ion-item-options:not(.item-options-end) {
width: 100%;
visibility: visible;
@@ -69,8 +69,8 @@ ion-item-options {
display: flex;
}
&.item-sliding-active-options-left .item-options-left,
&.item-sliding-active-options-right ion-item-options:not(.item-options-left) {
&.item-sliding-active-options-left .item-options-start,
&.item-sliding-active-options-right ion-item-options:not(.item-options-start) {
width: 100%;
visibility: visible;

View File

@@ -1,5 +1,5 @@
import { Component, Element, Event, EventEmitter, Method, Prop } from '@stencil/core';
import { Side, isRightSide } from '../../utils/helpers';
import { Side, isEndSide } from '../../utils/helpers';
@Component({
@@ -7,6 +7,9 @@ import { Side, isRightSide } from '../../utils/helpers';
styleUrls: {
ios: 'item-options.ios.scss',
md: 'item-options.md.scss'
},
host: {
theme: 'item-options'
}
})
export class ItemOptions {
@@ -28,8 +31,8 @@ export class ItemOptions {
@Event() ionSwipe!: EventEmitter<void>;
@Method()
isRightSide() {
return isRightSide(this.win, this.side);
isEndSide() {
return isEndSide(this.win, this.side);
}
@Method()
@@ -45,8 +48,8 @@ export class ItemOptions {
hostData() {
return {
class: {
'item-options-left': !this.isRightSide(),
'item-options-right': this.isRightSide()
'item-options-start': !this.isEndSide(),
'item-options-end': this.isEndSide()
}
};
}

View File

@@ -64,7 +64,7 @@ Emitted when the item has been fully swiped.
#### fireSwipeEvent()
#### isRightSide()
#### isEndSide()
#### width()

View File

@@ -118,7 +118,7 @@ export class ItemSliding {
for (let i = 0; i < options.length; i++) {
const option = options.item(i);
if (option.isRightSide()) {
if (option.isEndSide()) {
this.rightOptions = option;
sides |= ItemSide.Right;
} else {

View File

@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Item Sliding - Lines</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-header>
<ion-toolbar>
<ion-title>Item Sliding - Lines</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-list-header>Default List</ion-list-header>
<!-- Sliding items are generated below -->
</ion-list>
<ion-list lines="full">
<ion-list-header>Full List</ion-list-header>
<!-- Sliding items are generated below -->
</ion-list>
<ion-list lines="inset">
<ion-list-header>Inset List</ion-list-header>
<!-- Sliding items are generated below -->
</ion-list>
<ion-list lines="none">
<ion-list-header>No Lines List</ion-list-header>
<!-- Sliding items are generated below -->
</ion-list>
</ion-content>
<script>
var lists = document.getElementsByTagName('ion-list');
console.log(lists, lists.length);
for (var i = 0; i < lists.length; i++) {
console.log(lists[i]);
for (var j = 0; j < 3; j++) {
addSlidingItem(lists[i]);
}
}
function addSlidingItem(list) {
const slidingItem = document.createElement('ion-item-sliding');
slidingItem.innerHTML = `
<ion-item>
<ion-label>
<h2>Item Options Both Sides</h2>
</ion-label>
</ion-item>
<ion-item-options side="start">
<ion-item-option color="secondary" expandable>
<ion-icon name="ios-checkmark"></ion-icon>
Unread
</ion-item-option>
</ion-item-options>
<ion-item-options side="end">
<ion-item-option color="light">
<ion-icon name="mail"></ion-icon>
Archive
</ion-item-option>
<ion-item-option color="danger" expandable>
<ion-icon name="trash"></ion-icon>
Delete
</ion-item-option>
</ion-item-options>
`;
list.appendChild(slidingItem);
}
</script>
</ion-app>
</body>
</html>

View File

@@ -75,34 +75,42 @@
@media screen and (orientation: landscape) {
@include safe-area-padding-horizontal(null, $item-ios-padding-end / 2);
}
border-bottom: $hairlines-width solid $item-ios-border-color;
}
// iOS Items in Lists
// iOS Item Lines
// --------------------------------------------------
// Removed the requirement that their immmediate
// parent is listed this adds support for other list components
ion-list,
ion-reorder-group > ion-gesture {
> ion-item:first-child .item-ios,
> ion-item-sliding:first-child .item-ios {
border-top: $hairlines-width solid $item-ios-border-color;
}
> ion-item:last-child .item-ios,
> ion-item-sliding:last-child .item-ios {
border-bottom: $hairlines-width solid $item-ios-border-color;
}
> ion-item:last-child .item-ios .item-inner,
> ion-item-sliding:last-child .item-ios .item-inner {
border-bottom: 0;
}
.item-ios,
.item-ios .item-inner {
border-bottom-width: 0;
border-bottom-style: $item-ios-border-bottom-style;
border-bottom-color: $item-ios-border-bottom-color;
}
// Default item has inset border bottom
.item-ios .item-inner {
border-bottom-width: $item-ios-border-bottom-width;
}
// Full lines - apply the border to the item
// Inset lines - apply the border to the item inner
.item-ios-lines-full,
.item-ios-lines-inset .item-inner {
border-bottom-width: $item-ios-border-bottom-width;
}
// Full lines - remove the border from the item inner (inset list items)
// Inset lines - remove the border on the item (full list items)
// No lines - remove the border on both (full / inset list items)
.item-ios-lines-inset,
.item-ios-lines-full .item-inner,
.item-ios-lines-none,
.item-ios-lines-none .item-inner {
border-bottom-width: 0;
}
// iOS Item Slots
// --------------------------------------------------
@@ -189,6 +197,8 @@ ion-reorder-group > ion-gesture {
$color-tint: ion-color($colors-ios, $color-name, tint, ios);
.item-ios-#{$color-name} {
border-bottom-color: $color-shade;
color: $color-contrast;
background-color: $color-base;

View File

@@ -54,6 +54,18 @@ $item-ios-padding-bottom: 11px !default;
/// @prop - Padding start for the item content
$item-ios-padding-start: 16px !default;
/// @prop - Border bottom width for the item when lines are displayed
$item-ios-border-bottom-width: $hairlines-width !default;
/// @prop - Border bottom style for the item when lines are displayed
$item-ios-border-bottom-style: solid !default;
/// @prop - Border bottom color for the item when lines are displayed
$item-ios-border-bottom-color: $item-ios-border-color !default;
/// @prop - Border bottom for the item
$item-ios-border-bottom: $item-ios-border-bottom-width $item-ios-border-bottom-style $item-ios-border-bottom-color !default;
// Item Slots
// --------------------------------------------------

View File

@@ -5,7 +5,7 @@
// --------------------------------------------------
.item-md {
@include padding-horizontal($item-md-padding-start, 0);
@include padding-horizontal($item-md-padding-start, null);
position: relative;
@@ -20,12 +20,12 @@
transition: background-color 300ms cubic-bezier(.4, 0, .2, 1);
}
.item-md.activated {
background-color: $item-md-background-color-active;
.item-md .item-inner {
@include padding-horizontal(null, ($item-md-padding-end / 2));
}
.item-md[no-lines] {
border-width: 0;
.item-md.activated {
background-color: $item-md-background-color-active;
}
.item-md h1 {
@@ -64,42 +64,38 @@
color: $item-md-paragraph-text-color;
}
.item-md .item-inner {
@include padding-horizontal(null, ($item-md-padding-end / 2));
border-bottom: 1px solid $item-md-border-color;
}
// Material Design Items in Lists
// Material Design Item Lines
// --------------------------------------------------
// Removed the requirement that their immmediate
// parent is listed this adds support for other list components
ion-list,
ion-reorder-group > ion-gesture {
> ion-item:first-child .item-md,
> ion-item-sliding:first-child .item-md {
border-top: 1px solid $item-md-border-color;
}
> ion-item:last-child .item-md,
> ion-item-sliding:last-child .item-md {
border-bottom: 1px solid $item-md-border-color;
}
> ion-item:last-child .item-md .item-inner,
> ion-item-sliding:last-child .item-md .item-inner {
border-bottom: 0;
}
// Default item has no border bottom
.item-md,
.item-md .item-inner {
border-bottom-width: 0;
border-bottom-style: $item-md-border-bottom-style;
border-bottom-color: $item-md-border-bottom-color;
}
// If the item has the no-lines attribute remove the bottom border from:
// the item itself (for last-child items)
// the item-inner class (if it is not last)
ion-item[no-lines],
ion-item[no-lines] .item-inner {
border-width: 0;
// Default input items have a border
.item-md.item-input {
border-bottom-width: $item-md-border-bottom-width;
}
// Full lines - apply the border to the item
// Inset lines - apply the border to the item inner
.item-md-lines-full,
.item-md-lines-inset .item-inner {
border-bottom-width: $item-md-border-bottom-width;
}
// Full lines - remove the border from the item inner (inset list items)
// Inset lines - remove the border on the item (full list items)
// No lines - remove the border on both (full / inset list items)
.item-md-lines-inset,
.item-md-lines-full .item-inner,
.item-md-lines-none,
.item-md-lines-none .item-inner {
border-bottom-width: 0;
}
@@ -195,6 +191,8 @@ ion-item[no-lines] .item-inner {
$color-tint: ion-color($colors-md, $color-name, tint, md);
.item-md-#{$color-name} {
border-bottom-color: $color-shade;
color: $color-contrast;
background-color: $color-base;

View File

@@ -4,40 +4,52 @@
// --------------------------------------------------
/// @prop - Color of the item paragraph
$item-md-paragraph-text-color: $text-md-color-step-400 !default;
$item-md-paragraph-text-color: $text-md-color-step-400 !default;
/// @prop - Font family of the item
$item-md-font-family: $font-family-md-base !default;
$item-md-font-family: $font-family-md-base !default;
/// @prop - Font size of the item
$item-md-font-size: 16px !default;
$item-md-font-size: 16px !default;
/// @prop - Width of the avatar in the item
$item-md-avatar-width: 40px !default;
$item-md-avatar-width: 40px !default;
/// @prop - Height of the avatar in the item
$item-md-avatar-height: $item-md-avatar-width !default;
$item-md-avatar-height: $item-md-avatar-width !default;
/// @prop - Width of the thumbnail in the item
$item-md-thumbnail-width: 80px !default;
$item-md-thumbnail-width: 80px !default;
/// @prop - Height of the thumbnail in the item
$item-md-thumbnail-height: $item-md-thumbnail-width !default;
$item-md-thumbnail-height: $item-md-thumbnail-width !default;
/// @prop - Color of the detail arrow icon
$item-md-detail-push-color: $item-md-border-color !default;
$item-md-detail-push-color: $item-md-border-color !default;
/// @prop - Padding top for the item content
$item-md-padding-top: 13px !default;
$item-md-padding-top: 13px !default;
/// @prop - Padding end for the item content
$item-md-padding-end: 16px !default;
$item-md-padding-end: 16px !default;
/// @prop - Padding bottom for the item content
$item-md-padding-bottom: 13px !default;
$item-md-padding-bottom: 13px !default;
/// @prop - Padding start for the item content
$item-md-padding-start: 16px !default;
$item-md-padding-start: 16px !default;
/// @prop - Border bottom width for the item when lines are displayed
$item-md-border-bottom-width: 1px !default;
/// @prop - Border bottom style for the item when lines are displayed
$item-md-border-bottom-style: solid !default;
/// @prop - Border bottom color for the item when lines are displayed
$item-md-border-bottom-color: $item-md-border-color !default;
/// @prop - Border bottom for the item when lines are displayed
$item-md-border-bottom: $item-md-border-bottom-width $item-md-border-bottom-style $item-md-border-color !default;
// Item Slots

View File

@@ -62,11 +62,6 @@ ion-item {
text-overflow: ellipsis;
}
.item[no-lines],
.item.item[no-lines] .item-inner {
border: 0;
}
ion-item-group {
display: block;
}

View File

@@ -54,6 +54,11 @@ export class Item {
*/
@Prop() href?: string;
/**
* How the bottom border should be displayed on the item.
*/
@Prop() lines?: 'full' | 'inset' | 'none';
/**
* When using a router, it specifies the transition direction when navigating to
* another page using `href`.
@@ -121,6 +126,8 @@ export class Item {
...getElementClassMap(this.el.classList),
'item-disabled': this.disabled,
'item-detail-push': showDetail,
[`item-lines-${this.lines}`]: !!this.lines,
[`item-${this.mode}-lines-${this.lines}`]: !!this.lines
};
return (

View File

@@ -84,6 +84,13 @@ Contains a URL or a URL fragment that the hyperlink points to.
If this property is set, an anchor tag will be rendered.
#### lines
string
How the bottom border should be displayed on the item.
#### mode
string
@@ -142,6 +149,13 @@ Contains a URL or a URL fragment that the hyperlink points to.
If this property is set, an anchor tag will be rendered.
#### lines
string
How the bottom border should be displayed on the item.
#### mode
string

View File

@@ -53,7 +53,7 @@
</ion-label>
</ion-item>
<ion-item no-lines>
<ion-item lines="none">
<ion-label>
Single line item with no lines
</ion-label>

View File

@@ -0,0 +1,19 @@
'use strict';
const { By, until } = require('selenium-webdriver');
const { register, Page, platforms } = require('../../../../../scripts/e2e');
class E2ETestPage extends Page {
constructor(driver, platform) {
super(driver, `http://localhost:3333/src/components/item/test/lines?ionicplatform=${platform}`);
}
}
platforms.forEach(platform => {
describe('item/lines', () => {
register('should init', driver => {
const page = new E2ETestPage(driver, platform);
return page.navigate('#content');
});
});
});

View File

@@ -0,0 +1,219 @@
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="UTF-8">
<title>Item - Lines</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>Item Lines</ion-title>
</ion-toolbar>
</ion-header>
<ion-content id="content">
<!-- Default -->
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<!-- Lines Inset -->
<ion-item lines="inset">
<ion-label>Item Lines Inset</ion-label>
</ion-item>
<!-- Lines Full -->
<ion-item lines="full">
<ion-label>Item Lines Full</ion-label>
</ion-item>
<!-- Default -->
<ion-item>
<ion-icon name="star" slot="start"></ion-icon>
<ion-label>Item</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>
<!-- Lines Inset -->
<ion-item lines="inset">
<ion-icon name="star" slot="start"></ion-icon>
<ion-label>Item Lines Inset</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>
<!-- Lines Full -->
<ion-item lines="full">
<ion-icon name="star" slot="start"></ion-icon>
<ion-label>Item Lines Full</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>
<!-- Lines None -->
<ion-item lines="none">
<ion-icon name="star" slot="start"></ion-icon>
<ion-label>Item Lines None</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>
<!-- List Lines Full -->
<ion-list lines="full">
<ion-list-header>List Full Lines</ion-list-header>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item lines="inset">
<ion-label>Item Inset</ion-label>
</ion-item>
</ion-list>
<ion-list lines="inset">
<ion-list-header>
List Inset Lines
</ion-list-header>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item lines="full">
<ion-label>Item Full</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
<ion-list lines="none">
<ion-list-header>
List No Lines
</ion-list-header>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item lines="full">
<ion-label>Item Full</ion-label>
</ion-item>
<ion-item lines="inset">
<ion-label>Item Inset</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
<h2>Colors</h2>
<!-- Default -->
<ion-item color="secondary">
<ion-label>Item</ion-label>
</ion-item>
<!-- Lines Inset -->
<ion-item color="secondary" lines="inset">
<ion-label>Item Lines Inset</ion-label>
</ion-item>
<!-- Lines Full -->
<ion-item color="secondary" lines="full">
<ion-label>Item Lines Full</ion-label>
</ion-item>
<!-- Default -->
<ion-item color="danger">
<ion-icon name="star" slot="start"></ion-icon>
<ion-label>Item</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>
<!-- Lines Inset -->
<ion-item color="danger" lines="inset">
<ion-icon name="star" slot="start"></ion-icon>
<ion-label>Item Lines Inset</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>
<!-- Lines Full -->
<ion-item color="danger" lines="full">
<ion-icon name="star" slot="start"></ion-icon>
<ion-label>Item Lines Full</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>
<!-- Lines None -->
<ion-item color="danger" lines="none">
<ion-icon name="star" slot="start"></ion-icon>
<ion-label>Item Lines None</ion-label>
<ion-icon name="information-circle" slot="end"></ion-icon>
</ion-item>
<!-- List Lines Full -->
<ion-list lines="full">
<ion-list-header>List Full Lines</ion-list-header>
<ion-item color="light">
<ion-label>Item</ion-label>
</ion-item>
<ion-item color="light">
<ion-label>Item</ion-label>
</ion-item>
<ion-item color="light" lines="inset">
<ion-label>Item Inset</ion-label>
</ion-item>
</ion-list>
<ion-list lines="inset">
<ion-list-header>
List Inset Lines
</ion-list-header>
<ion-item color="dark">
<ion-label>Item</ion-label>
</ion-item>
<ion-item color="dark" lines="full">
<ion-label>Item Full</ion-label>
</ion-item>
<ion-item color="dark">
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
<ion-list lines="none">
<ion-list-header>
List No Lines
</ion-list-header>
<ion-item color="tertiary">
<ion-label>Item</ion-label>
</ion-item>
<ion-item color="tertiary" lines="full">
<ion-label>Item Full</ion-label>
</ion-item>
<ion-item color="tertiary" lines="inset">
<ion-label>Item Inset</ion-label>
</ion-item>
<ion-item color="tertiary">
<ion-label>Item</ion-label>
</ion-item>
<ion-item color="tertiary">
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
</ion-content>
</ion-app>
<script>
function testClick(ev) {
console.log('CLICK!', ev.target.tagName, ev.target.textContent.trim());
}
</script>
</body>
</html>

View File

@@ -53,7 +53,7 @@
</ion-label>
</ion-item>
<ion-item no-lines>
<ion-item lines="none">
<ion-label>
Single line item with no lines
</ion-label>

View File

@@ -54,7 +54,7 @@
</ion-label>
</ion-item>
<ion-item no-lines>
<ion-item lines="none">
<ion-label>
Single line item with no lines
</ion-label>

View File

@@ -23,7 +23,9 @@ Basic Usage
</ion-item>
<ion-item color="secondary">
<ion-label>Secondary Color Item</ion-label>
<ion-label>
Secondary Color Item
</ion-label>
</ion-item>
```
@@ -53,18 +55,23 @@ List Items
```html
<ion-list>
<ion-item>
Item
<ion-label>
Item
</ion-label>
</ion-item>
<ion-item no-lines>
No Lines Item
<ion-item lines="none">
<ion-label>
No Lines Item
</ion-label>
</ion-item>
<ion-item text-wrap>
<ion-label>
Multiline text that should wrap when it is too long
to fit on one line in the item.
</ion-label>
</ion-item>
<ion-item text-wrap>
@@ -79,9 +86,68 @@ List Items
</ion-label>
</ion-item>
<ion-item lines="full">
<ion-label>
Item with Full Lines
</ion-label>
</ion-item>
</ion-list>
```
Item Lines
```html
<!-- Item Inset Lines -->
<ion-item lines="inset">
<ion-label>Item Lines Inset</ion-label>
</ion-item>
<!-- Item Full Lines -->
<ion-item lines="full">
<ion-label>Item Lines Full</ion-label>
</ion-item>
<!-- Item None Lines -->
<ion-item lines="none">
<ion-label>Item Lines None</ion-label>
</ion-item>
<!-- List Full Lines -->
<ion-list lines="full">
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
<!-- List Inset Lines -->
<ion-list lines="inset">
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
<!-- List No Lines -->
<ion-list lines="none">
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
```
Media Items
```html

View File

@@ -23,7 +23,9 @@ Basic Usage
</ion-item>
<ion-item color="secondary">
<ion-label>Secondary Color Item</ion-label>
<ion-label>
Secondary Color Item
</ion-label>
</ion-item>
```
@@ -53,18 +55,23 @@ List Items
```html
<ion-list>
<ion-item>
Item
<ion-label>
Item
</ion-label>
</ion-item>
<ion-item no-lines>
No Lines Item
<ion-item lines="none">
<ion-label>
No Lines Item
</ion-label>
</ion-item>
<ion-item text-wrap>
<ion-label>
Multiline text that should wrap when it is too long
to fit on one line in the item.
</ion-label>
</ion-item>
<ion-item text-wrap>
@@ -79,9 +86,68 @@ List Items
</ion-label>
</ion-item>
<ion-item lines="full">
<ion-label>
Item with Full Lines
</ion-label>
</ion-item>
</ion-list>
```
Item Lines
```html
<!-- Item Inset Lines -->
<ion-item lines="inset">
<ion-label>Item Lines Inset</ion-label>
</ion-item>
<!-- Item Full Lines -->
<ion-item lines="full">
<ion-label>Item Lines Full</ion-label>
</ion-item>
<!-- Item None Lines -->
<ion-item lines="none">
<ion-label>Item Lines None</ion-label>
</ion-item>
<!-- List Full Lines -->
<ion-list lines="full">
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
<!-- List Inset Lines -->
<ion-list lines="inset">
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
<!-- List No Lines -->
<ion-list lines="none">
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
<ion-item>
<ion-label>Item</ion-label>
</ion-item>
</ion-list>
```
Media Items
```html

View File

@@ -8,15 +8,6 @@
@include margin(-1px, $list-ios-margin-end, $list-ios-margin-bottom, $list-ios-margin-start);
}
// If the item has the no-lines attribute remove the bottom border from:
// the item itself (for last-child items)
// the item-inner class (if it is not last)
.list-ios .item[no-lines],
.list-ios .item[no-lines] .item-inner {
border-width: 0;
}
.list-ios:not([inset]) + .list-ios:not([inset]) ion-list-header {
@include margin(-$list-ios-margin-top, null, null, null);
@include padding(0, null, null, null);
@@ -61,8 +52,38 @@
// iOS No Lines List
// --------------------------------------------------
.list-ios[no-lines] ion-list-header,
.list-ios[no-lines] .item,
.list-ios[no-lines] .item-inner {
border-width: 0;
.list-ios-lines-none .item-ios,
.list-ios-lines-none .item-ios .item-inner {
border-bottom-width: 0;
}
// iOS Full Lines List
// --------------------------------------------------
.list-ios-lines-full .item-ios,
.list-ios .item-ios-lines-full {
border-bottom-width: $list-ios-item-border-bottom-width;
}
.list-ios-lines-full .item-ios .item-inner {
border-bottom-width: 0;
}
// iOS Inset Lines List
// --------------------------------------------------
.list-ios-lines-inset .item-ios .item-inner,
.list-ios .item-ios-lines-inset .item-inner {
border-bottom-width: $list-ios-item-border-bottom-width;
}
// Remove the border from items in lists
// if they are explicitly styled by the item
// to be different than the list
.list-ios .item-ios-lines-full .item-inner,
.list-ios .item-ios-lines-inset {
border-bottom-width: 0;
}

View File

@@ -1,5 +1,7 @@
@import "../../themes/ionic.globals.ios";
@import "../item/item.ios.vars";
// iOS List
// --------------------------------------------------
@@ -15,6 +17,9 @@ $list-ios-margin-bottom: 32px !default;
/// @prop - Margin start of the list
$list-ios-margin-start: 0 !default;
/// @prop - Border bottom of the item in a list
$list-ios-item-border-bottom-width: $item-ios-border-bottom-width !default;
/// @prop - Margin top of the inset list
$list-inset-ios-margin-top: 16px !default;

View File

@@ -48,11 +48,37 @@
background-color: $item-md-background-color;
}
// Material Design No Lines List
// --------------------------------------------------
.list-md[no-lines] .item-md,
.list-md[no-lines] .item-md .item-inner {
border-width: 0;
.list-md-lines-none .item-md,
.list-md-lines-none .item-md .item-inner {
border-bottom-width: 0;
}
// Material Design Full Lines List
// --------------------------------------------------
.list-md-lines-full .item-md,
.list-md .item-md-lines-full {
border-bottom-width: $list-md-item-border-bottom-width;
}
// Material Design Inset Lines List
// --------------------------------------------------
.list-md-lines-inset .item-md .item-inner,
.list-md .item-md-lines-inset .item-inner {
border-bottom-width: $list-md-item-border-bottom-width;
}
// Remove the border from items in lists
// if they are explicitly styled by the item
// to be different than the list
.list-md .item-md-lines-full .item-inner,
.list-md .item-md-lines-inset {
border-bottom-width: 0;
}

View File

@@ -1,31 +1,36 @@
@import "../../themes/ionic.globals.md";
@import "../item/item.md.vars";
// Material Design List
// --------------------------------------------------
/// @prop - Margin top of the list
$list-md-margin-top: 16px !default;
$list-md-margin-top: 16px !default;
/// @prop - Margin end of the list
$list-md-margin-end: 0 !default;
$list-md-margin-end: 0 !default;
/// @prop - Margin bottom of the list
$list-md-margin-bottom: 16px !default;
$list-md-margin-bottom: 16px !default;
/// @prop - Margin start of the list
$list-md-margin-start: 0 !default;
$list-md-margin-start: 0 !default;
/// @prop - Border bottom of the item in a list
$list-md-item-border-bottom-width: $item-md-border-bottom-width !default;
/// @prop - Margin top of the inset list
$list-inset-md-margin-top: 16px !default;
$list-inset-md-margin-top: 16px !default;
/// @prop - Margin end of the inset list
$list-inset-md-margin-end: 16px !default;
$list-inset-md-margin-end: 16px !default;
/// @prop - Margin bottom of the inset list
$list-inset-md-margin-bottom: 16px !default;
$list-inset-md-margin-bottom: 16px !default;
/// @prop - Margin start of the inset list
$list-inset-md-margin-start: 16px !default;
$list-inset-md-margin-start: 16px !default;
/// @prop - Border radius of the inset list
$list-inset-md-border-radius: 2px !default;
$list-inset-md-border-radius: 2px !default;

View File

@@ -1,4 +1,5 @@
import { Component, Method } from '@stencil/core';
import { Component, Method, Prop } from '@stencil/core';
import { Mode } from '../../interface';
@Component({
tag: 'ion-list',
@@ -11,9 +12,14 @@ import { Component, Method } from '@stencil/core';
}
})
export class List {
private mode!: Mode;
private openItem?: HTMLIonItemSlidingElement;
/**
* How the bottom border should be displayed on all items.
*/
@Prop() lines?: 'full' | 'inset' | 'none';
/**
* Get the [Item Sliding](../../item-sliding/ItemSliding) that is currently opene.
*/
@@ -44,4 +50,13 @@ export class List {
return false;
}
hostData() {
return {
class: {
[`list-lines-${this.lines}`]: !!this.lines,
[`list-${this.mode}-lines-${this.lines}`]: !!this.lines
}
};
}
}

View File

@@ -11,6 +11,24 @@ reorder items within the list, and deleting items.
<!-- Auto Generated Below -->
## Properties
#### lines
string
How the bottom border should be displayed on all items.
## Attributes
#### lines
string
How the bottom border should be displayed on all items.
## Methods
#### closeSlidingItems()

View File

@@ -34,7 +34,7 @@
<ion-item>Doom</ion-item>
<ion-item>Fallout</ion-item>
<ion-item>GTA</ion-item>
<ion-item>Halo</ion-item>
<ion-item lines="full">Halo</ion-item>
</ion-list>
</ion-content>

View File

@@ -11,7 +11,7 @@ const BOX_SHADOW_WIDTH = 8;
export default function(Animation: Animation, _: HTMLElement, menu: Menu): Promise<Animation> {
let closedX: string, openedX: string;
const width = menu.width + BOX_SHADOW_WIDTH;
if (menu.isRightSide) {
if (menu.isEndSide) {
// right side
closedX = width + 'px';
openedX = '0px';

View File

@@ -12,7 +12,7 @@ export default function(Animation: Animation, _: HTMLElement, menu: Menu): Promi
let contentOpenedX: string, menuClosedX: string;
const width = menu.width;
if (menu.isRightSide) {
if (menu.isEndSide) {
contentOpenedX = -width + 'px';
menuClosedX = width + 'px';

View File

@@ -8,7 +8,7 @@ import baseAnimation from './base';
* The menu itself, which is under the content, does not move.
*/
export default function(Animation: Animation, _: HTMLElement, menu: Menu): Promise<Animation> {
const openedX = (menu.width * (menu.isRightSide ? -1 : 1)) + 'px';
const openedX = (menu.width * (menu.isEndSide ? -1 : 1)) + 'px';
const contentOpen = new Animation()
.addElement(menu.contentEl)

View File

@@ -1,6 +1,6 @@
import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Method, Prop, State, Watch } from '@stencil/core';
import { Animation, Config, GestureDetail, MenuChangeEventDetail, Mode } from '../../interface';
import { Side, assert, isRightSide } from '../../utils/helpers';
import { Side, assert, isEndSide } from '../../utils/helpers';
@Component({
tag: 'ion-menu',
@@ -31,7 +31,7 @@ export class Menu {
@Element() el!: HTMLIonMenuElement;
@State() isRightSide = false;
@State() isEndSide = false;
@Prop({ context: 'config' }) config!: Config;
@Prop({ context: 'isServer' }) isServer!: boolean;
@@ -89,7 +89,7 @@ export class Menu {
@Watch('side')
protected sideChanged() {
this.isRightSide = isRightSide(this.win, this.side);
this.isEndSide = isEndSide(this.win, this.side);
}
/**
@@ -281,7 +281,7 @@ export class Menu {
} else if (this.menuCtrl!.getOpen()) {
return false;
}
return checkEdgeSide(this.win, detail.currentX, this.isRightSide, this.maxEdgeStart);
return checkEdgeSide(this.win, detail.currentX, this.isEndSide, this.maxEdgeStart);
}
private onWillStart(): Promise<void> {
@@ -307,7 +307,7 @@ export class Menu {
return;
}
const delta = computeDelta(detail.deltaX, this._isOpen, this.isRightSide);
const delta = computeDelta(detail.deltaX, this._isOpen, this.isEndSide);
const stepValue = delta / this.width;
this.animation.progressStep(stepValue);
}
@@ -318,8 +318,8 @@ export class Menu {
return;
}
const isOpen = this._isOpen;
const isRightSide = this.isRightSide;
const delta = computeDelta(detail.deltaX, isOpen, isRightSide);
const isEndSide = this.isEndSide;
const delta = computeDelta(detail.deltaX, isOpen, isEndSide);
const width = this.width;
const stepValue = delta / width;
const velocity = detail.velocityX;
@@ -331,8 +331,8 @@ export class Menu {
&& (velocity < -0.2 || detail.deltaX < -z);
const shouldComplete = (isOpen)
? isRightSide ? shouldCompleteRight : shouldCompleteLeft
: isRightSide ? shouldCompleteLeft : shouldCompleteRight;
? isEndSide ? shouldCompleteRight : shouldCompleteLeft
: isEndSide ? shouldCompleteLeft : shouldCompleteRight;
let shouldOpen = (!isOpen && shouldComplete);
if (isOpen && !shouldComplete) {
@@ -418,14 +418,14 @@ export class Menu {
}
hostData() {
const isRightSide = this.isRightSide;
const isEndSide = this.isEndSide;
return {
role: 'complementary',
class: {
[`menu-type-${this.type}`]: true,
'menu-enabled': !this.disabled,
'menu-side-right': isRightSide,
'menu-side-left': !isRightSide,
'menu-side-right': isEndSide,
'menu-side-left': !isEndSide,
}
};
}
@@ -459,12 +459,12 @@ export class Menu {
}
}
function computeDelta(deltaX: number, isOpen: boolean, isRightSide: boolean): number {
return Math.max(0, (isOpen !== isRightSide) ? -deltaX : deltaX);
function computeDelta(deltaX: number, isOpen: boolean, isEndSide: boolean): number {
return Math.max(0, (isOpen !== isEndSide) ? -deltaX : deltaX);
}
function checkEdgeSide(win: Window, posX: number, isRightSide: boolean, maxEdgeStart: number): boolean {
if (isRightSide) {
function checkEdgeSide(win: Window, posX: number, isEndSide: boolean, maxEdgeStart: number): boolean {
if (isEndSide) {
return posX >= win.innerWidth - maxEdgeStart;
} else {
return posX <= maxEdgeStart;

View File

@@ -27,7 +27,7 @@ export class SelectPopover {
render() {
return (
<ion-list no-lines={this.mode === 'md'}>
<ion-list>
{ this.header ? <ion-list-header>{this.header}</ion-list-header> : null }
{ this.subHeader || this.message
? <ion-item text-wrap>

View File

@@ -443,6 +443,7 @@ export class Select {
private emitStyle() {
this.ionStyle.emit({
'input': true,
'select': true,
'select-disabled': this.disabled,
'input-has-value': this.hasValue()

View File

@@ -43,12 +43,12 @@ export type Side = 'start' | 'end';
/**
* @hidden
* Given a side, return if it should be on the right
* Given a side, return if it should be on the end
* based on the value of dir
* @param side the side
* @param isRTL whether the application dir is rtl
*/
export function isRightSide(win: Window, side: Side): boolean {
export function isEndSide(win: Window, side: Side): boolean {
const isRTL = win.document.dir === 'rtl';
switch (side) {
case 'start': return isRTL;